In Perl werden anonyme Subroutinen und Closures unterstützt. Anonyme Subroutinen werden über sub ohne Namen deklariert und geben einen Verweis auf den Code zurück. Ein Closure ist eine Subroutine, die den lexikalischen Geltungsbereich erfasst, einschließlich der Variablen, die bei ihrer Erstellung existierten.
Beispiel für eine anonyme Subroutine und Closure:
sub make_incrementer { my $inc = shift; return sub { $_[0] + $inc }; } my $inc10 = make_incrementer(10); print $inc10->(5); # Gibt 15 aus
Closures werden aktiv zur Erstellung von Funktionsfabriken, Generatoren und Callbacks verwendet (z. B. in map/grep, Ereignis-Handlern).
Ein wichtiger Punkt: Wenn ein Closure auf Variablen verweist, die ihrerseits auf das Closure zeigen (direkt oder über eine Struktur), entsteht eine zyklische Referenz und es kann zu einem Speicherleck kommen.
Wann werden Variablen, die in einem Closure geschlossen sind, freigegeben? Gibt es einen Unterschied im Verhalten für
myundour?
Antwort: Variablen my, die innerhalb eines Closures geschlossen sind, bleiben so lange alive, wie es mindestens einen Verweis auf das Closure selbst gibt. Sie werden nicht nach Abschluss der Funktion freigegeben, ihre Lebensdauer entspricht der gesamten Lebensdauer des Closures. Für our-Variablen gibt es dieses Verhalten nicht – sie sind für alle Closures verfügbar und werden am Ende des Programms freigegeben. Wenn man vergisst, das Closure zu löschen, können Speicherlecks auftreten.
Beispiel für ein Problem:
my $cref; { my $val = 5; $cref = sub { $val++ }; } # $val existiert weiterhin, solange $cref lebt
Geschichte
In einer Serveranwendung wurde für jeden Benutzer ein Closure-Kontext für Callbacks erstellt. Aber das Closure verwies auch auf die Benutzerstruktur, was zu einer zyklischen Referenz führte. Dadurch konnte der Garbage Collector die Benutzerobjekte auch nach dem Logout nicht bereinigen – die Speicherlecks wuchsen exponentiell.
Geschichte
In einer Daemon-Anwendung zur Hintergrundverarbeitung von Ereignissen wurden Closures mit geschlossenen Zähler-Variablen verwendet, aber es wurde vergessen, die Arrays, auf die sie verwiesen, zu leeren. Das Ergebnis – aufgrund von ein paar vergessenen Closures sammelten sich versehentlich alte Nachrichten-Daten, bis der Daemon abstürzte und eine manuelle Bereinigung des Heaps notwendig wurde.
Geschichte
Ein Entwickler versuchte, eine
our-Variable in einem Closure zu verwenden, in der Erwartung eines "geschlossenen" Verhaltens – aber alle Closures teilten sich eine Variable, was zu Datenrennen bei gleichzeitiger Ausführung führte. Der Fehler trat auf, als Benutzer gleichzeitig mit verschiedenen Parametern arbeiteten (falsche Berechnungen).