Historisch gesehen unterstützt Perl den lexikalischen Gültigkeitsbereich von Variablen, was die Verwendung von Closures — Funktionen, die ihre äußere Umgebung speichern — ermöglicht. Das Problem entsteht, wenn ein Closure auf Variablen außerhalb seines Gültigkeitsbereichs verweist oder wenn eingebettete Strukturen zyklische Verweise erzeugen, was zu Speicherlecks aufgrund unsachgemäßer Handhabung von Verweisen führt.
Die Lösung besteht darin, Closures zu verwenden, um Funktionalitäten und einen funktionalen Stil zu schaffen, während man sich an das richtige Verwalten von Verweisen beim Schließen von Variablen aus dem äußeren Gültigkeitsbereich erinnert.
Beispielcode:
sub make_counter { my $count = 0; return sub { $count++; }; } my $counter = make_counter(); print $counter->(), "\n"; # 0 print $counter->(), "\n"; # 1
Wichtige Besonderheiten:
Was passiert, wenn man eine anonyme Funktion zurückgibt, die auf sich selbst verweist?
Es wird ein zyklischer Verweis erstellt, den Perl nicht automatisch mit dem Garbage Collector sammeln kann. Dies führt zu einem Speicherleck. Zur Lösung verwenden Sie schwache Verweise, modul Scalar::Util:
use Scalar::Util qw(weaken); my $foo; $foo = sub { ... $foo ... }; weaken($foo);
Erfasst ein Closure immer eine „Kopie“ der Variablen oder ist es ein Verweis auf dieselbe Variable?
Ein Closure arbeitet immer mit der aktuellen Variable, ihr Gültigkeitsbereich wird beim Erstellen des Closures festgelegt. Somit ist die Variable für alle Aufrufe der Closure-Funktion dieselbe.
Kann man ein Closure erstellen, das mit veränderlichen Zuständen außerhalb von sich arbeitet, aber keinen festen Verweis darauf behält?
Ja, verwenden Sie schwache Verweise (Scalar::Util::weaken) oder strukturieren Sie den Code so, dass Verweise nur dort gehalten werden, wo es erforderlich ist (zum Beispiel geben Sie die Daten bei jedem Aufruf des Closures von außen weiter).
Ein Callback-Closure erstellt, das $self aus einem OO-Objekt schließt und innerhalb eines Hashs von Callbacks gespeichert wird. Nach der Zerstörung des Objekts wird der Speicher nicht freigegeben.
Vorteile:
Nachteile:
Ein Closure verweist korrekt schwach auf $self mit Hilfe von Scalar::Util::weaken:
use Scalar::Util qw(weaken); my $cb = sub { my $self = shift; weaken($self); ... };
Vorteile:
Nachteile: