简体   繁体   English

Perl map / grep内存泄漏

[英]Perl map/grep memory leak

I have been working on a perl project at work, and came across a strange memory leak. 我一直在研究工作中的perl项目,并遇到了一个奇怪的内存泄漏。 I have boiled down the source of my problem into a contrived example: 我把我的问题的根源归结为一个人为的例子:

#!/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($_);
#}

Uncomment 1 of the 4 blocks of code (beneath the subroutines) at a time and run the script while monitoring its memory usage. 取消注释4个代码块中的1个(在子例程下面)并在监视其内存使用情况时运行脚本。 On my machine, the code that uses grep or map appear to cause memory leaks, whereas the "loop equivalent"s do not. 在我的机器上,使用grep或map的代码似乎会导致内存泄漏,而“循环等效”则不会。 My perl version is v5.10.1, and I am running Ubuntu. 我的perl版本是v5.10.1,我正在运行Ubuntu。

I believe this could be a bug in perl, but I don't want to jump to a drastic conclusion without another opinion on what could be the cause. 我相信这可能是perl中的一个错误,但我不想在没有关于可能的原因的另一个意见的情况下跳到一个激烈的结论。 Can anyone explain if this behaviour is correct? 任何人都可以解释这种行为是否正确?

Thanks 谢谢

I don't know if it is a memory leak as such. 我不知道这是否是内存泄漏。 If I lower the top value of your loop (say, from 100000 to 100), I can use the map / grep expressions repeatedly without losing memory. 如果我降低循环的最高值(例如,从100000到100),我可以重复使用map / grep表达式而不会丢失内存。

Rather, it seems more likely that map and grep are atomic operations when it comes to memory management, that perl is not performing its garbage collection in the middle of those operations. 相反,当涉及内存管理时, mapgrep似乎更有可能是原子操作,perl在这些操作的中间不执行其垃圾收集。

Perl 5.12.0 (and 5.8.9) do seem a bit more robust on these kind of expressions (but they also seem to be slower). Perl 5.12.0(和5.8.9)在这些表达式上确实看起来更强大(但它们似乎也更慢)。

It really is. 它确实是。 But to prove so, you have to put while(1){} around suspicious expression - in perl, memory that is once acquired never returns to OS (but can be reused by perl itself). 但为了证明这一点,你必须将while(1){}置于可疑表达式之外 - 在perl中,曾经获得的内存永远不会返回到OS(但可以由perl本身重用)。 I've run code with 我用的是代码

while(1){ grep { f($_) } (1..100000) } while(1){grep {f($ _)}(1..100000)}

under 5.8.8 and it constantly grows in size - so, it's a leak. 5.8.8以下,它的大小不断增加 - 所以,这是一个泄漏。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM