2010-07-29 12 views
6

Pracowałem nad projektem perl w pracy i natknąłem się na dziwny wyciek pamięci. Mam sprowadzić źródło mojego problemu w contrived przykład:Perl map/grep memory leak

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

Odkomentuj 1 z 4 bloków kodu (pod podprogramów) w czasie i uruchomić skrypt podczas monitorowania jej zużycia pamięci. Na moim komputerze kod, który korzysta z grep lub mapy wydaje się powodować wycieki pamięci, podczas gdy "ekwiwalent pętli" nie. Moja wersja perl to v5.10.1, a ja używam Ubuntu.

Wierzę, że to może być błąd w perlu, ale nie chcę przeskoczyć do drastycznego wniosku bez innej opinii na temat tego, co może być przyczyną. Czy ktoś może wyjaśnić, czy to zachowanie jest poprawne?

Dzięki

Odpowiedz

2

ja nie wiem, czy to jest przeciek pamięci jako takiej. Jeśli obniżę najwyższą wartość twojej pętli (powiedzmy od 100000 do 100), będę mógł wielokrotnie używać wyrażeń map/grep bez utraty pamięci.

Raczej wydaje się bardziej prawdopodobne, że map i grep są operacjami atomowymi, jeśli chodzi o zarządzanie pamięcią, że perl nie wykonuje swojego czyszczenia pamięci w środku tych operacji.

Perl 5.12.0 (i 5.8.9) wydają się nieco bardziej odporne na tego rodzaju wyrażenia (ale także wydają się wolniejsze).

1

To naprawdę jest. Ale żeby to udowodnić, musisz umieścić (1) {} wokół podejrzanego wyrażenia - w perlu, pamięć, która jest raz zdobyta, nigdy nie wraca do systemu operacyjnego (ale może być ponownie wykorzystana przez samego perla). Zabrakło mi kod z

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

pod 5.8.8 i stale rośnie w wielkości - tak, to jest przeciek .