2010-07-29 6 views
6

Ich habe an einem Perl-Projekt gearbeitet und bin auf ein merkwürdiges Speicherleck gestoßen. Ich habe die Quelle meines Problems in ein konstruiertes Beispiel kocht: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($_); 
#} 

Kommentar- 1 der 4 Codeblöcke (unterhalb der Unterprogramme) zu einem Zeitpunkt, und das Skript ausführen, während seine Speichernutzung zu überwachen. Auf meinem Computer scheint der Code, der grep oder map verwendet, Speicherlecks zu verursachen, während die "Schleifenäquivalente" dies nicht tun. Meine Perl-Version ist v5.10.1, und ich benutze Ubuntu.

Ich glaube, das könnte ein Fehler in Perl sein, aber ich möchte nicht zu einer drastischen Schlussfolgerung ohne eine andere Meinung über das, was die Ursache sein könnte, springen. Kann jemand erklären, ob dieses Verhalten korrekt ist?

Dank

Antwort

2

Ich weiß nicht, ob es sich um ein Speicherleck als solche ist. Wenn ich den oberen Wert Ihrer Schleife absenke (zB von 100000 auf 100), kann ich die map/grep Ausdrücke wiederholt verwenden, ohne Speicher zu verlieren.

Eher scheint es, dass map und grep atomare Operationen sind, wenn es um Speicherverwaltung geht, dass Perl seine Garbage Collection nicht in der Mitte dieser Operationen ausführt.

Perl 5.12.0 (und 5.8.9) scheinen bei diesen Ausdrücken etwas robuster zu sein (aber sie scheinen auch langsamer zu sein).

1

Es ist wirklich. Aber um das zu beweisen, müssen Sie while (1) {} um verdächtige Ausdrücke setzen - in Perl kehrt einmal erlangter Speicher niemals zu OS zurück (kann aber von Perl selbst wiederverwendet werden). Ich habe Code ausführen mit

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

unter 5.8.8 und es wächst ständig in der Größe - so, es ist ein Leck .