我的代码如下:
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
的内存?
答案 0 :(得分:13)
如果您使用过strict
和warnings
,那么您会看到:
参考文献找到了偶数大小的预期列表
A行和B行不按照您的想法行事。它们实际上将对空哈希的引用的字符串化版本指定为键,并将undef作为其值。即使哈希现在几乎为空,内存也不会被标记为可重用,因为你没有使用正确的语句。
尝试在A行和B行使用以下语句之一:
undef %var; # this one
%var = (); # or this one
答案 1 :(得分:7)
答案 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})