Утечка памяти в Perl - PullRequest
6 голосов
/ 29 июля 2010

Я работал над проектом на 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($_);
#}

Раскомментируйте 1 из 4 блоков кода (под подпрограммами) за раз и запустите скрипт, следя за использованием его памяти.На моей машине код, использующий grep или map, вызывает утечку памяти, тогда как код, эквивалентный циклу, этого не делает.Моя версия Perl v5.10.1, и я использую Ubuntu.

Я считаю, что это может быть ошибкой в ​​Perl, но я не хочу делать резкий вывод без другого мнения о том, что может быть причиной.Кто-нибудь может объяснить, если это поведение правильно?

Спасибо

Ответы [ 2 ]

2 голосов
/ 29 июля 2010

Не знаю, утечка памяти как таковая.Если я уменьшу верхнее значение вашего цикла (скажем, с 100000 до 100), я смогу многократно использовать выражения map / grep без потери памяти.

Скорее, скорее всего, map и grep являются атомарными операциями, когда дело доходит до управления памятью, когда perl не выполняет сборку мусора в середине этих операций.

Perl 5.12.0 (и 5.8.9) кажется немного более устойчивым к выражениям такого типа (но они также кажутся более медленными).

1 голос
/ 31 июля 2010

Это действительно так. Но чтобы доказать это, вы должны поместить while (1) {} в подозрительное выражение - в perl память, которая когда-то была получена, никогда не возвращается в ОС (но может быть использована самим perl). Я запустил код с

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

ниже 5.8.8, и он постоянно увеличивается в размерах - значит, это утечка.

...