我一直在研究工作中的perl项目,并遇到了一个奇怪的内存泄漏。我已将问题的根源归结为一个人为的例子:
#!/usr/bin/perl
use strict;
use warnings;
# takes: an array reference
# returns: 1
sub g {
my ($a) = @_;
return 1;
}
# takes: nothing
# returns: the result of applying g on an array reference
sub f {
my @a = ('a') x 131072; # allocate roughly a megabyte
return g(\@a);
}
# causes a leak:
#map { f($_) } (1..100000);
# loop equivalent to map, no leak:
#my @b;
#for my $i (1..100000) {
# push @b, f($_);
#}
# causes a leak:
#grep { f($_) } (1..100000);
# loop equivalent to grep, no leak:
#my @b;
#for my $i (1..100000) {
# push @b, $i if f($_);
#}
一次取消注释4个代码块中的1个(在子例程下面),并在监视其内存使用情况时运行脚本。在我的机器上,使用grep或map的代码似乎会导致内存泄漏,而“循环等效”则不会。我的perl版本是v5.10.1,我正在运行Ubuntu。
我相信这可能是perl中的一个错误,但我不想在没有关于可能的原因的另一个意见的情况下跳到一个激烈的结论。任何人都可以解释这种行为是否正确吗?
由于
答案 0 :(得分:2)
我不知道这是否是内存泄漏。如果我降低循环的最高值(例如,从100000到100),我可以重复使用map
/ grep
表达式而不会丢失内存。
相反,在内存管理方面,map
和grep
似乎更可能是原子操作,而perl在这些操作过程中不会执行垃圾收集。
Perl 5.12.0(和5.8.9)在这些表达式上确实看起来更强大(但它们似乎也更慢)。
答案 1 :(得分:1)
确实如此。但为了证明这一点,你必须将while(1){}置于可疑表达式之外 - 在perl中,曾经获得的内存永远不会返回到OS(但可以由perl本身重用)。我用
运行代码while(1){grep {f($ _)}(1..100000)}
<5.8>低于5.8.8并且它的大小不断增加 - 所以,这是一个泄漏。