Was hält lokal gespeicherte Objekte am Leben, wenn Listener registriert sind?

8

Ich sehe diese Art von scheinbarer Magie in allen Arten von AS3-Code, aber hier ist ein reduziertes Beispiel:

%Vor%

Wie im Code-Kommentar angegeben, sollte die loader -Variable nach dem URLLoaderExample -Konstruktor nicht mehr in den Gültigkeitsbereich fallen. Jedoch ... scheint es immernoch am Leben zu bleiben (nicht Müll gesammelt), da der onComplete Listener / Handler es sauber empfangen kann.

Wo ist der magische / versteckte / globale Verweis auf loader , der ihn am Leben erhält, damit er seine Ladeoperation abschließen kann, und dann an den onComplete Listener / Callback übergeben wird? Kann diese Referenz irgendwo gesehen werden?

Um mit Kontext zu helfen ... als ein ähnliches Beispiel, weiß ich, dass die Instanz loader den onComplete Listener registriert hat. Ich weiß auch, dass ich vorsichtig sein muss, um removeEventListener zu jeder Zeit (?) Zu verwenden, um mögliche Speicherlecks zu vermeiden, die von gestrandeten Zuhörern herrühren. Was mich beunruhigt ist, dass ich nicht verstehe, wo die magische loader Referenz ist und ob (oder wann) ich das aufräumen muss.

Ist es vielleicht der loader.load() Aufruf selbst, der loader irgendwo global stopft?

    
Russ 05.07.2011, 06:41
quelle

4 Antworten

5

Dieses Beispiel ist definitiv fehleranfällig, da loader vor Abschluss des Ladevorgangs eine Müllsammlung erhalten kann. Wenn Sie COMPLETE event mit der Methode onComplete abonnieren, erstellen Sie eine Referenz von loader für Ihre Klasse URLLoaderExample . Und was Sie tun müssen, um sicherzustellen, dass GC den Lader nicht ruiniert, ist die Erstellung einer Referenz zu .

GC garantiert Ihnen jedoch niemals eine rechtzeitige Reinigung, selbst wenn Sie alle Referenzen explizit löschen. ( Siehe diesen Beitrag für Ressourcen zu GC Logiken. ) Aber kann einen Loader sammeln, wenn es keine expliziten Referenzen darauf gibt. Wenn Sie Ihren Test in einer App ausführen, die Speicher verwendet (und nicht nur dort sitzt und nichts tut), werden Sie wahrscheinlich dieses Verhalten sehen. Und es ist viel wahrscheinlicher, dass Lade-Müll gesammelt wird, wenn Sie versuchen, swfs anstelle von Daten zu laden.

Die Verwendung schwacher Referenzen hilft hier nicht, denn wenn Sie dies tun, sagen Sie GC: "Fühlen Sie sich frei zu töten, was ich, der Dispatcher, referenziere, ich habe kein Mitleid dafür." In Ihrem Beispiel würde es so aussehen: "Sie können die URLLoaderExample -Instanz töten, wenn sie andere brauchbare Referenzen verliert", was sinnlos ist. Hier ist ein guter Artikel über useWeakReference.

Listener verhindern nicht, dass ein Dispatcher von einem Garbage-Collector erfasst wird. Ein inaktives Objekt ist eines, das keine Referenzen mehr von anderen aktiven Objekten hat. Wenn also ein Objekt selbst Referenzen auf etwas Externes hat, verhindert es nicht, dass dieses Objekt aus dem Speicher entfernt wird.

Also, um Ihre Frage kurz zu beantworten: Die Referenz ist nirgends, Sie haben nur Glück, dass das Laden funktioniert. Nun, um ganz genau zu sein, ist es das Funktion Aktivierungsobjekt (wie es in der ECMA-Spezifikation genannt wird), das als ein Bereich für lokale Variablen verwendet wird und sie referenziert. Aber auf jeden Fall wird es bei der Methodenrückgabe entsorgt, und Sie können niemals einen Verweis auf das Aktivierungsobjekt selbst erhalten (wiederum per Spezifikation).

BEARBEITEN Noch ein paar Worte darüber, wer die Müllsammlung hält. Wegen offensichtlicher Missverständnisse in Kommentaren hinzugefügt.

Ein Zitat von Adobe livedocs :

  

useWeakReference: Boolean (default = false) - Bestimmt, ob der Verweis auf den Listener stark oder schwach ist. Ein starker Verweis (der Standardwert) verhindert, dass Ihr Listener als Garbage Collection erfasst wird. Eine schwache Referenz nicht.

Die Subskription für das Ereignis erstellt also eine Referenz FROM Dispatcher TO Listener. Und der Disponent kann im Gegensatz zum Zuhörer frei gehen. Listener verhindern nicht, dass ein Dispatcher als Müll gesammelt wird. Und der Dispatcher KANN verhindern, dass Hörer von Müll gesammelt werden, weshalb wir useWeakReference haben.

    
Nox Noctis 05.07.2011, 08:04
quelle
1

Wenn Sie einen Ereignis-Listener hinzufügen, erstellen Sie implizit einen Verweis auf das Loader-Objekt (standardmäßig). Sie können dies jedoch entfernen, indem Sie den Eventlistener auf einen "schwachen" Verweis setzen.

So würden Sie das tun:

%Vor%

Das letzte Argument setzt "useWeakListener" auf "true", was bedeutet, dass kein Verweis auf den Loader erfolgt. In diesem Fall sollte der Lader GC'ed sein.

Es ist wichtig zu beachten, dass Sie, wenn Sie einen Ereignis-Listener mit einer starken Referenz hinzufügen, diese entfernen müssen (wie im Beispiel). Wenn Sie einen schwachen Listener verwenden, müssen Sie den Loader zu einer privaten Variable in der Klasse machen, andernfalls befindet sich Ihr Callback in einer Rennsituation mit dem GC.

Hier ist die Dokumentation zur Methode: Ссылка

    
Shakakai 05.07.2011 06:51
quelle
1

Nun, Mann, wenn Ihre Frage war, warum der Loader außerhalb des Geltungsbereichs ist, hier ist Ihre Antwort:

Tatsächlich ist das Ladeprogramm, das Sie in der Klassenkonstruktormethode (CCM) sehen, nicht dasselbe, das Sie in onComplete sehen: LINE14: var loader:URLLoader = URLLoader(evt.target);

(Ich weiß nicht, warum Leute den gleichen Namen auf Variablen setzen, das kann verwirrend sein, aber das ist jetzt nicht der Fall, den ich erklären werde)

Die Magie liegt in evt.target . Aber Sie sollten sich fragen: "Was macht die .target ?" Nun, es ist eine Instanzvariable, die durch das "Event Object" definiert ist, und sie stellt eine Referenz auf das "Zielobjekt" bereit.

Wenn Sie nicht wissen, was ein "Ereignisziel" ist, lesen Sie diesen Absatz. Das "Event Target" ist das Objekt, in dem der Listener bei LINE9 registriert wurde: loader.addEventListener(Event.COMPLETE, onComplete); Wie Sie sehen können, ist es der Loader am CCM (bitte verwechseln Sie die Loader-Namen nicht), der sich auf new URLLoader(); bezieht. Fazit: Das "Event Target" ist das URLLoader-Objekt, auf das von der lokalen Variablen load am CCM verwiesen wird.

Nun, mit der .target-Variable können Sie auf das URLLoader-Objekt verweisen und dann die Referenz verwenden, wie Sie möchten. In diesem Fall haben Sie den Verweis verwendet, um den Listener zu entfernen. Es ist okay.

Hier ist eine verbesserte Version (nur eine Instanzvariable, die einen Verweis auf URLLoader liefert):

%Vor%

Aber nur um sicherzustellen, dass Sie nicht mit den Namen verwechselt werden:

%Vor%

Prost ... Wenn Sie irgendwelche Zweifel am Casting-Vorgang haben, den Sie bei URLLoader(evt.target); verwenden, können Sie fragen.

    
Gabriel 11.07.2012 03:33
quelle
0

Ich verstehe deine Verwirrung nicht. Die loader-Variable tut den Gültigkeitsbereich (der Verweis, auf den Sie im Speicher verwiesen haben, wird nicht mehr benötigt). Da jedoch immer noch ein Verweis auf einen externen Ereignis-Listener vorhanden ist, wird der Ladevorgang selbst nicht mit GC durchgeführt, weshalb Sie weiterhin den Verweis des Ladeprogramms abrufen können (im Handler erhält er das Ziel) und ist nicht berechtigt für GC, bis der Ereignislistener entfernt wird.

BEARBEITEN: Entschuldigung, ich sollte in dieser Angelegenheit klarer sein. Ich hätte mehr Kaffee trinken sollen. Wenn ich "external" meine, meine ich Dinge wie Loader, da sie von einer Browseraktion abhängig sind. Nun, ich kann das nicht sicher sagen, da ich nie den zugrunde liegenden Code für Flash Player gesehen habe, aber mein Verdacht ist, dass wenn Sie Loader-Klassen haben, die mit dem Browser interagieren müssen, eine Unterstreichungsreferenz ( vom Spieler zum Loader), was es davon abhält, GC'ed zu werden. Deshalb sollten Sie Ihre Loader immer entladen oder so, das ist mein Verständnis des Flash Players. Ich könnte mich irren, aber ich habe in der Vergangenheit mehrere Tests gemacht und ich habe noch nie einen externen Listener gesehen (in diesem Fall Loader), aber ich frage mich, ob es noch andere externe Listener gibt geschehen mit Air) bekomme GC ohne explizit zu sein.

    
J_A_X 05.07.2011 15:37
quelle

Tags und Links