首页 文章

Perl:如何在不访问Perl变量的情况下释放为标量分配的内存?

提问于
浏览
8

这个问题与Perl的前question about memory handling有关answer有关 . 我已经知道可以通过在可用标量上显式使用 undef 函数并使用 Devel::PeekDevel::Size 来释放Perl中的内存,或者这样可以看到为标量分配了多少内存 . 在所有这些情况下,调试的标量都在其范围内使用 .

但是有可能在变量范围之外调试分配内存之类的东西,只是在Perl解释器的层面上吗?有点像为当前解释器中的标量搜索所有“事物”的所有已分配内存并打印其相关数据,如当前值等?

如果是这样的话,如果一个人已经有了这些信息,那么是否能够释放已知的记忆?就像在标量上调用 undef ,但没有标量,更低级别的东西,比如 Devel::Peek 的"things"输出 .

我正在考虑的是在请求之后执行mod_perl清理处理程序,扫描当前mod_perl解释器以获取大块数据并手动释放它们 . 仅仅因为我认为大块分配的数据不再有用,即使Perl认为不是这样:

最后,也许最大的胜利是内存重用:当调用Perl子程序时,内存分配是在第一次使用它们时为变量做出的 . 随后使用变量可以分配更多的内存,例如如果标量变量需要保存比之前更长的字符串,或者数组中添加了新元素 . 作为优化,Perl会挂起这些分配,即使它们的值“超出范围” .

https://perl.apache.org/docs/2.0/user/intro/overview.html#Threads_Support

我可以找到很多关于低级内存访问的监视和调试包,但是没有提示如何在Perl中的某些低级Perl结构上调用 undef 函数 . 如果没有任何XS或类似的话,可能根本不可能......

3 回答

  • 1

    是否可以在变量范围之外调试分配的内存等内容

    真的没有这样的记忆 . 肯定需要在变量之外分配的任何内存 . 正如你自己指出的那样,它是为构成最“浪费”空间的变量分配的内存 .

    但是没有提示如何在Perl中的某些低级Perl结构上调用undef函数 .

    这是因为没有这样的结构 .

    就像在标量上调用undef一样,但没有标量,更低级别的东西,比如Devel :: Peek的那些“东西”输出 .

    Devel :: Peek唯一的函数 Dump ,输出变量中的东西 . 就像你说过的那样, undef 就是你想要清除它们的东西 .


    从上面可以看出,你很想知道如何释放与subs中变量相关的内存 .

    您还忽略了这样一个事实,即许多运算符都有一个关联变量(称为“目标”),在该变量中返回结果 .

    方法1

    清除所有这些变量的一种简单方法是选择性地清除符号表( %:: ) . 这实际上是"unload"每个模块 . 请务必不要清除核心组件( perl -E'say for sort keys %::' ) . 并且不要忘记清除 %INC 以便可以重新加载模块 .

    如果清除符号表是您要采用的方法,那么在早期拍摄 %:: 的快照可能会降低风险和时间,并在清除符号时恢复该快照 .

    方法2

    如果你不想重新加载模块,你可以尝试找到每个sub,并取消他们的vars,然后取消他们的ops的vars .

    子的变量存在于pads中 . 方便的是,操作码目标也是如此 . 对于子经历的每个级别的递归都有一个填充 .

    给定对sub的引用,您可以在子垫中找到变量 . 有关如何执行此操作的示例,请参阅PadWalker . 您实际上不能使用PadWalker,因为它只返回每个变量名称一个变量,即使有多个变量名称(由于多个变量声明的名称相同,或者由于递归) .

    捕获的变量和 our 变量应保持不变 . 可以检测填充条目是否是其中之一 . (再次,请参阅PadWalker . )

    (显然,你也可以考虑释放sub的额外垫!)

    你怎么找到所有潜艇?那么,导航符号表将为您提供大部分 . 寻找一个人将会比较棘手 .

    方法3

    最有效的方法是简单地终止mod_perl线程/进程 . 将自动生成一个新的干净的 . 它's also the simplest to implement, as it'只是一个配置更改(将 MaxRequestsPerChild 设置为 1 ) .


    另一种形式的浪费内存是内存泄漏 . 这是另一个大问题,所以我没有触及它 .

  • -1

    我想你正在寻找类似的问题this answer . 你真正需要知道的一切都可以在Devel :: MAT :: *子模块的内部找到 . 即Devel::MAT::Dumper.xs,它具有perl解释器的堆结构 . 该模块旨在将堆转储到信号并稍后进行分析,但我认为您可以将其转换为运行时检查 . 如果您在阅读XS时需要帮助,请查看here .

  • 4

    要调试内存分配,您应该使用 -Accflags=-DPERL_MEM_LOG DOC重新编译perl

    (见关于how to recompile perl的相关问题)

    你可能会对MEMORY DEBUGGERS感兴趣

    释放perl标量,就像它离开她的范围一样:

    { # Scope enter
         my $x; # Memory allocation
    } # << HERE $x is freed
    

    您应该通过 SvREFCNT_decDOC将其变量 REFCNT 减少为零

    要释放您创建的SV,请调用SvREFCNT_dec(SV *) . 通常这种调用是不必要的(参见参考计数和死亡率) .

    这是伪代码:

    { 
        $x;
        call_xs_sub( $x ); # << HERE $x is freed        
    }
    

    XS伪代码:

    call_xs_sub( SV *sv ) {
        ...
        SvREFCNT_dec( sv ); # <<HERE scalar is freed
        ...
    }
    

    To spy every memory allocation you should walk perl arenas.

    在编译时,您可以在B::Xref模块的帮助下查看声明和访问变量的每个位置

    或者使用 -Dm 选项运行perl(perl应该使用相应的选项进行编译 . 请参阅topic):

    perl -Dm script.pl
    

相关问题