In Perl wird der Speicher für Variablen und Datenstrukturen durch ein Referenzzählmechanismus (Reference Counting) verwaltet. Ein Objekt oder eine Struktur wird freigegeben, wenn der Referenzzähler auf null sinkt.
Dieser Mechanismus erkennt jedoch keine zirkulären Referenzen. Wenn Objekte sich gegenseitig referenzieren, erreichen ihre Zähler nicht null und der Speicher wird nicht freigegeben.
Zur Bereinigung zirkulärer Referenzen werden verwendet:
Scalar::Util::weaken. Eine schwache Referenz erhöht den Referenzzähler nicht, sodass der GC das Objekt freigeben kann, wenn es keine anderen starken Referenzen gibt.Beispiel für die Erstellung einer schwachen Referenz:
use Scalar::Util 'weaken'; my $parent = {}; my $child = { parent => $parent }; $parent->{child} = $child; weaken($child->{parent}); # jetzt stört parent->child->parent nicht die Bereinigung
Kann Perl selbst zirkuläre Referenzen "erkennen" und freigeben ohne das Modul Scalar::Util oder manuelle Eingriffe?
Nein, Perl kann standardmäßig zirkuläre Strukturen nicht automatisch "sammeln", da dieser Mechanismus eine Analyse der Objektgraphstruktur erfordert (wie zum Beispiel GC in JVM oder Python). Daher muss man sich immer selbst um die Bereinigung von Zyklen kümmern.
Geschichte
Im Sitzungsspeicher eines Webanwendungsservers wurden aktiv User-Objekte mit bidirektionalen Beziehungen verwendet. Es stellte sich heraus, dass der Speicher des Prozesses nach mehreren Tausend Aufrufen aufgrund von Zyklen wuchs: $user->{session}->{user} = $user. Das Leck verschwand nach der Einführung von weaken für die Rückreferenzen.
Geschichte
Bei der Verwendung eines Caches mit LRU-Algorithmus wurden Objektketten über Referenzen verknüpft. Die Entwickler haben nicht für die manuelle Nullung der Verbindungen gesorgt, was zu einem plötzlichen Anstieg des Speichers nach einigen Tagen Betriebs des Dienstes und einem Absturz aufgrund von OOM führte.
Geschichte
In einem komplexen Mikrodienst zur Dokumentenspeicherung wurden bei der Berichtsgenerierung eval und großflächige Datenstrukturen mit zirkulären Referenzen verwendet. Die Entwickler rechneten mit der automatischen Müllsammlung von Perl, aber der Server "merkte" sich alte Objekte und verlor nach einer Woche des Betriebs den gesamten verfügbaren RAM. Die Diagnostik fand Zyklen und verwendete Scalar::Util nach jedem Bericht.