如何在Perl中释放内存?

时间:2012-01-19 10:04:12

标签: perl garbage-collection

我的代码如下:

 my %var;
 my %var_new={};

 while(1){
     while(my ($k,$v)=each %var){
            &a_sub($v);
     }
     %var={}; # A
     map { $var{$_}=$var_new{$_}; } keys %var_new;
     %var_new={}; # B
 }

 sub a_sub { #....} # will fill %var_new

我程序的内存使用率一直在上升。

似乎Perl没有在A行和B行释放内存。

如何手动制作Perl以释放使用%var%var_new的内存?

4 个答案:

答案 0 :(得分:13)

如果您使用过strictwarnings,那么您会看到:

  

参考文献找到了偶数大小的预期列表

A行和B行不按照您的想法行事。它们实际上将对空哈希的引用的字符串化版本指定为键,并将undef作为其值。即使哈希现在几乎为空,内存也不会被标记为可重用,因为你没有使用正确的语句。

尝试在A行和B行使用以下语句之一:

undef %var; # this one
%var = ();  # or this one

答案 1 :(得分:7)

IIRC,一旦Perl从操作系统分配了内存,它就会在进程的生命周期内保留在内存中。在可能的情况下,Perl将重用已经分配的内存而不是向操作系统询问更多内容,但是您不会看到进程使用的内存减少。

答案 2 :(得分:1)

我认为使用undef函数:

undef %var, %var_new;

可能会成功。 当然,如果你不再需要那些哈希内部的东西了

答案 3 :(得分:1)

可以通过undef将内存释放回OS。但是$var = undef;undef($var);

之间是有区别的

$var = undef;除了重置对象的标志外不执行任何操作。大小仍然相同

undef($var);实际上确实删除了指针并释放了该对象的内存-当且仅当这是“原始”变量时。

有一个有趣的Lightning Talk from Cees Hek - To undef or not to undef

例如,以下代码在调用undef之后几乎恢复了其原始内存使用率(在Perl 5.30.0 Fedora 31,libc 2.30上进行了测试)

#!perl

use feature 'say';

say "PID: $$";
say "Before Alloc";
<STDIN>;

my $large_string = "A" x 100000000;

say "After Alloc - Before undef";
<STDIN>;

undef($large_string);

say "After undef";
<STDIN>;

但是 ...这并不意味着您仅在调用undef之后,复杂的数据结构便会释放所有内存。

以下示例说明了该问题: 主要内存使用者是$sneaky。调用undef(%hash)之后,由于$sneaky仍然存在,内存使用率几乎保持不变。

#!perl

use feature 'say';
use Devel::Peek;
$Devel::Peek::pv_limit = 15;

say "PID: $$";
say "BEFORE ALLOC";
<STDIN>;

my $sneaky = "A" x 100000000;
my %hash;
$hash{large_string_inside} = $sneaky;

say "After Alloc - Before undef";
say '$sneaky:';
Dump($sneaky);

say '%hash:';
Dump(%hash);

<STDIN>;

undef(%hash);

say "After undef";

say '$sneaky:';
Dump($sneaky);


say '%hash:';
Dump(%hash);

<STDIN>;

即使遍历结构并在每个元素上调用undef也是不够的(嵌套结构也是如此-您可以递归地遍历它们,但不会有任何作用)。

while(my ($k, $v) = each %hash) {
    undef($v); # THIS IS NOT ENOUGH
}

为什么?因为我们没有删除原始的$sneaky。将内存还给操作系统的唯一方法是调用undef($sneaky)

如果您像这样$sneaky%hash中放入$hash{large_string_inside} = \$sneaky;的引用,也会没有有所不同 您仍然需要致电undef($sneaky)而不是undef($hash{large_string_inside})