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

Perl: How to free memory allocated for a scalar without access to the Perl variable?

这个问题与 Perl 的 to a former 有关。我了解到可以通过在可用标量上显式使用 undef 函数并使用 Devel::PeekDevel::Size 来释放 Perl 中的内存,或者这样可以看到为一个分配了多少内存标量。在所有这些情况下,调试的标量都在其范围内使用。

但是是否可以仅在 Perl 解释器的级别上调试变量范围之外的分配内存之类的东西?比如搜索当前解释器中标量的所有 "things" 的所有分配内存并打印它们的相关数据,如当前值等?

如果是这样的话,如果已经有了该信息,是否能够释放已知内存?就像在标量上调用 undef,但没有标量,更底层的东西,比如 Devel::Peek.

的 "things" 输出

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

Finally and perhaps the biggest win is memory re-use: as calls are made into Perl subroutines, memory allocations are made for variables when they are used for the first time. Subsequent use of variables may allocate more memory, e.g. if a scalar variable needs to hold a longer string than it did before, or an array has new elements added. As an optimization, Perl hangs onto these allocations, even though their values "go out of scope".

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

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

我认为您正在寻找 this answer 类似的问题。 您真正需要知道的一切都可以在 Devel::MAT::* 子模块的内部找到。即 Devel::MAT::Dumper.xs, which has the structure of the heap for perl interpreter. The module is designed to dump the heap at signal and analyze it later, but I think you can turn it into a runtime check. If you need help on reading the XS, look here.

要调试内存分配,您应该使用 -Accflags=-DPERL_MEM_LOG DOC

重新编译 perl

(参见有关 的相关问题)

您可能会对MEMORY DEBUGGERS

感兴趣

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

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

你应该通过 SvREFCNT_decDOC

将它的变量 REFCNT 减少到零

To free an SV that you've created, call SvREFCNT_dec(SV*) . Normally this call is not necessary (see Reference Counts and Mortality).

伪代码如下:

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

XS伪代码:

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

要监视每个内存分配,您应该走 perl arenas。

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

或运行带-Dm选项的perl(perl应该用相应的选项编译。见):

perl -Dm script.pl

is it possible to debug things like allocated memory outside the scope of variables

真的没有这样的记忆。肯定需要在变量之外分配的任何内存。正如您自己指出的那样,它是为构成大多数 "wasted" space.

的变量分配的内存

but no hint yet how one could call something like the undef function on some low level Perl struct in Perl.

因为没有这样的结构

Just like calling undef on a scalar, but without the scalar, something more low level, like on those "things" output of Devel::Peek.

Devel::Peek 的唯一函数,Dump,输出 in 变量。正如您所说,undef 是您想要清除的内容。


从上面的内容可以看出,您想知道如何释放与 subs 中的变量关联的内存。

您还忽略了一个事实,即许多运算符都有一个关联变量(称为 "target"),在其中 return 他们的结果。

方法一

清除所有这些变量的一种简单方法是有选择地清除符号 table (%::)。这将有效地 "unload" 每个模块。一定不要清除核心组件(perl -E'say for sort keys %::')。并且不要忘记清除 %INC 以便重新加载模块。

如果清除符号 table 是您想要采用的方法,那么尽早为 %:: 拍摄快照并在拍摄时恢复该快照可能风险较小且耗时较少是时候清除符号了。

方法二

如果您不想重新加载模块,您可以尝试定位每个子模块,并取消定义它们的变量,然后取消定义它们的操作变量。

子程序的变量存在于其 pads 中。方便的是,操作码目标也是如此。潜艇经历的每个递归级别都有一个垫。

给定对潜艇的引用,您可以在潜艇的焊盘中找到变量。您可以参考 PadWalker 以获取有关如何执行此操作的示例。你实际上不能使用 PadWalker,因为每个变量名只有 returns 一个变量,即使有多个变量(由于多个变量被声明为同名,或者由于递归)。

捕获的变量和our变量应该保持不变。可以检测 pad 条目是否是其中之一。 (再次参考 PadWalker。)

(显然,您也可以考虑释放低音炮的额外垫子!)

你如何找到所有的潜艇?好吧,导航符号 table 将为您提供其中的大部分内容。寻找匿名者会更棘手。

方法 3

最有效的方法是简单地终止 mod_perl thread/process。将自动生成一个新的干净的。它也是最简单的实现方式,因为它只是一个配置更改(将 MaxRequestsPerChild 设置为 1)。


另一种形式的内存浪费是内存泄漏。这是另一个大问题,所以我不碰它。