Unlimited Plugins, WordPress themes, videos & courses! Unlimited asset downloads! From $16.50/m
Advertisement
  1. Code
  2. Workflow

Grundbegriffe von Garbage Collection in AS3

by
Read Time:16 minsLanguages:

German (Deutsch) translation by Alex Grigorovich (you can also view the original English article)

Haben Sie jemals eine Flash-App verwendet und eine Verzögerung festgestellt? Sie wissen immer noch nicht, warum dieses coole Flash-Spiel auf Ihrem Computer langsam läuft? Wenn Sie mehr über eine mögliche Ursache erfahren möchten, ist dieser Artikel genau das Richtige für Sie.

Wir haben diesen großartigen Autor dank FlashGameLicense.com gefunden, dem Ort, an dem Sie Flash-Spiele kaufen und verkaufen können!

Neu veröffentlichtes Tutorial

Alle paar Wochen besuchen wir einige der Lieblingsbeiträge unserer Leser aus der gesamten Geschichte der Website. Dieses Tutorial wurde erstmals im Juni 2010 veröffentlicht.


Vorschau des Endergebnisses

Werfen wir einen Blick auf das Endergebnis, auf das wir hinarbeiten werden:


Schritt 1: Ein kurzer Überblick über die Referenzierung

Bevor wir uns mit dem eigentlichen Theme befassen, müssen Sie zunächst wissen, wie das Instanziieren und Referenzieren in AS3 funktioniert. Wenn Sie bereits darüber gelesen haben, empfehle ich dennoch, diesen kleinen Schritt zu lesen. Auf diese Weise wird das gesamte Wissen in Ihrem Kopf frisch und Sie werden keine Probleme haben, den Rest dieses Quick-Tipps zu lesen!

Das Erstellen und Referenzieren von Instanzen in AS3 unterscheidet sich von den meisten Menschen. Die Instanziierung (oder "Erstellung") von etwas erfolgt nur, wenn der Code zum Erstellen eines Objekts auffordert. Normalerweise geschieht dies über das Schlüsselwort "new", aber es ist auch vorhanden, wenn Sie beispielsweise eine Literal-Syntax verwenden oder Parameter für Funktionen definieren. Beispiele können Sie unten finden:

Nachdem ein Objekt erstellt wurde, bleibt es allein, bis etwas darauf verweist. Dazu erstellen Sie in der Regel eine Variable und übergeben den Wert des Objekts an die Variable, damit diese weiß, welches Objekt sie aktuell enthält. Wenn Sie jedoch den Wert einer Variablen an eine andere Variable übergeben (und dies ist der Teil, den die meisten Menschen nicht kennen), erstellen Sie kein neues Objekt. Sie erstellen stattdessen einen weiteren Link zu dem Objekt, das beide Variablen jetzt enthalten! Siehe das Bild unten zur Verdeutlichung:

Das Bild geht davon aus, dass sowohl Variable 1 als auch Variable 2 den Smiley enthalten können (d.h. Sie können denselben Typ enthalten). Auf der linken Seite existiert nur Variable 1. Wenn wir jedoch Variable 2 erstellen und auf den gleichen Wert wie Variable 1 setzen, erstellen wir keine Verknüpfung zwischen Variable 1 und Variable 2 (oberer rechter Teil des Bildes), sondern eine Verknüpfung zwischen Smiley und Variable 2 (rechts unten im Bild).

Mit diesem Wissen können wir zum Garbage Collector springen.


Schritt 2: Jede Stadt braucht Garbage Collector

Es ist offensichtlich, dass jede Anwendung eine bestimmte Menge an Speicher benötigt, um ausgeführt zu werden, da Variablen erforderlich sind, um Werte zu speichern und diese zu verwenden. Unklar ist, wie die Anwendung die nicht mehr benötigten Objekte verwaltet. Recycelt es sie? Löscht es sie? Lässt es das Objekt im Speicher, bis die Anwendung geschlossen wird? Alle drei Optionen können auftreten, aber hier werden wir speziell auf die zweite und dritte Option eingehen.

Stellen Sie sich eine Situation vor, in der eine Anwendung bei der Initialisierung viele Objekte erstellt. Nach Ablauf dieses Zeitraums bleibt jedoch mehr als die Hälfte der erstellten Objekte unbenutzt. Was würde passieren, wenn sie in Erinnerung bleiben würden? Sie würden sicherlich viel Platz darin beanspruchen, was zu einer lag führt, die eine merkliche Verlangsamung der Anwendung darstellt. Die meisten Benutzer würden dies nicht mögen, daher müssen wir es vermeiden. Wie können wir codieren, um die Anwendung effizienter auszuführen? Die Antwort ist im Garbage Collector.

Der Garbage Collector ist eine Form der Speicherverwaltung. Ziel ist es, alle Objekte zu entfernen, die nicht verwendet werden und Speicherplatz im Systemspeicher belegen. Auf diese Weise kann die Anwendung mit minimaler Speichernutzung ausgeführt werden. Mal sehen, wie es funktioniert:

Wenn Ihre Anwendung gestartet wird, fordert sie vom System eine Speichermenge an, die von der Anwendung verwendet wird. Die Anwendung startet und füllt diesen Speicher mit allen Informationen, die Sie benötigen. Jedes Objekt, das Sie erstellen, geht hinein. Wenn sich die Speichernutzung jedoch dem ursprünglich angeforderten Speicher nähert, wird der Garbage Collector ausgeführt und sucht nach Objekten, die nicht zum Leeren von Speicherplatz im Speicher verwendet werden. Manchmal führt dies aufgrund des großen Overheads bei der Objektsuche zu einer gewissen Verzögerung in der Anwendung.

Im Bild sehen Sie die Speicherspitzen (grün eingekreist). Die Spitzen und der plötzliche Abfall werden durch den Garbage Collector verursacht, der wirkt, wenn die Anwendung die angeforderte Speichernutzung erreicht hat (rote Linie) und alle unnötigen Objekte entfernt.


Schritt 3: Starten der SWF-Datei

Jetzt, da wir wissen, was der Garbage Collector für uns tun kann, ist es Zeit zu lernen, wie man programmiert, um alle Vorteile daraus zu ziehen. Zunächst müssen wir wissen, wie der Garbage Collector in praktischer Hinsicht funktioniert. Im Code sind Objekte für die Garbage Collection berechtigt, wenn sie nicht mehr erreichbar sind. Wenn auf ein Objekt nicht zugegriffen werden kann, versteht der Code, dass es nicht mehr verwendet wird, und muss daher gesammelt werden.

Actionscript 3 überprüft die Erreichbarkeit über Garbage Collection-Wurzeln. In dem Moment, in dem auf ein Objekt nicht über eine Garbage Collection-Wurzel zugegriffen werden kann, kann es gesammelt werden. Unten sehen Sie eine Liste der wichtigsten Garbage Collection-Wurzeln:

  • Paketebene und statische Variablen.
  • Lokale Variablen und Variablen im Bereich einer ausführenden Methode oder Funktion.
  • Instanzvariablen aus der Hauptklasseninstanz der Anwendung oder aus der Anzeigeliste.

Um zu verstehen, wie Objekte vom Garbage Collector behandelt werden, müssen wir codieren und untersuchen, was in der Beispieldatei geschieht. Ich werde das AS3-Projekt von FlashDevelop und den Compiler von Flex verwenden, aber ich gehe davon aus, dass Sie dies mit jeder gewünschten IDE tun können, da wir keine spezifischen Dinge verwenden werden, die nur in FlashDevelop vorhanden sind. Ich habe eine einfache Datei mit einer Schaltfläche und einer Textstruktur erstellt. Da dies in diesem kurzen Tipp nicht das Ziel ist, werde ich es kurz erklären: Wenn auf eine Schaltfläche geklickt wird, wird eine Funktion ausgelöst. Wenn Sie Text auf dem Bildschirm anzeigen möchten, rufen Sie eine Funktion mit dem Text auf und dieser wird angezeigt. Es gibt auch ein weiteres Textfeld, in dem eine Beschreibung für Schaltflächen angezeigt wird.

Das Ziel unserer Beispieldatei ist es, Objekte zu erstellen, zu löschen und zu untersuchen, was mit ihnen passiert, nachdem sie gelöscht wurden. Wir müssen wissen, ob das Objekt lebt oder nicht, also fügen wir jedem der Objekte einen ENTER_FRAME-Listener hinzu und lassen sie mit der Zeit, in der sie leben, Text anzeigen. Codieren wir also das erste Objekt!

Ich habe ein lustiges Smiley-Bild für die Objekte erstellt, als Hommage an Michael James Williams 'großartiges Avoider-Spiel-Tutorial, in dem auch Smiley-Bilder verwendet werden. Jedes Objekt hat eine Nummer auf dem Kopf, damit wir es identifizieren können. Außerdem habe ich das erste Objekt TheObject1 und das zweite Objekt TheObject2 benannt, damit es leicht zu unterscheiden ist. Gehen wir zum Code:

Das zweite Objekt sieht fast gleich aus. Hier ist es:

Im Code sind newObjectSimple1() und newObjectSimple2() Funktionen, die ausgelöst werden, wenn auf die entsprechende Schaltfläche geklickt wird. Diese Funktionen erstellen einfach ein Objekt und fügen es auf dem Bildschirm hinzu, sodass wir wissen, dass es erstellt wurde. Darüber hinaus wird in jedem Objekt ein ENTER_FRAME-Ereignis-Listener erstellt, mit dem jede Sekunde eine Nachricht angezeigt wird, solange sie aktiv sind. Hier sind die Funktionen:

Diese Funktionen zeigen einfach eine Meldung auf dem Bildschirm mit der Zeit an, zu der die Objekte gelebt haben. Hier ist die SWF-Datei mit dem aktuellen Beispiel:


Schritt 4: Löschen der Objekte

Nachdem wir uns nun mit der Erstellung von Objekten befasst haben, versuchen wir etwas: Haben Sie sich jemals gefragt, was passieren würde, wenn Sie ein Objekt tatsächlich löschen (alle Referenzen entfernen)? Wird Müll gesammelt? Das werden wir jetzt testen. Wir werden zwei Löschschaltflächen erstellen, eine für jedes Objekt. Machen wir den Code für sie:

Werfen wir jetzt einen Blick auf die SWF. Was denkst du wird passieren?

Wie Sie sehen. Wenn Sie auf "Objekt1 erstellen" und dann auf "Objekt1 löschen" klicken, passiert nichts wirklich! Wir können feststellen, dass der Code ausgeführt wird, da der Text auf dem Bildschirm angezeigt wird. Warum wird das Objekt jedoch nicht gelöscht? Das Objekt ist noch vorhanden, da es nicht entfernt wurde. Als wir alle Verweise darauf gelöscht haben, haben wir den Code angewiesen, ihn für die Speicherbereinigung zu qualifizieren, aber der Speicherbereinigungsprogramm wird nie ausgeführt. Denken Sie daran, dass der Garbage Collector nur ausgeführt wird, wenn sich die aktuelle Speichernutzung dem angeforderten Speicher nähert, als die Anwendung gestartet wurde. Es macht Sinn, aber wie werden wir das testen?

Ich werde sicherlich keinen Code schreiben, um unsere Anwendung mit nutzlosen Objekten zu füllen, bis die Speichernutzung zu groß wird. Stattdessen werden wir laut Grant Skinners Artikel eine Funktion verwenden, die derzeit von Adobe nicht unterstützt wird und die Ausführung des Garbage Collector erzwingt. Auf diese Weise können wir diese einfache Methode auslösen und sehen, was passiert, wenn sie ausgeführt wird. Von nun an werde ich Garbage Collector der Einfachheit halber auch als GC bezeichnen. Hier ist die Funktion:

Es ist bekannt, dass diese einfache Funktion, die nur zwei LocalConnection() -Objekte erstellt, die Ausführung des GC erzwingt. Wir werden sie daher aufrufen, wenn dies geschehen soll. Ich empfehle nicht, diese Funktion in einer ernsthaften Anwendung zu verwenden. Wenn Sie es zu Testzwecken ausführen, gibt es keine wirklichen Probleme. Wenn es sich jedoch um eine Anwendung handelt, die an andere Personen verteilt wird, ist dies keine gute Funktion, da dies negative Auswirkungen haben kann.

Was ich für solche Fälle empfehle, ist, dass Sie den GC einfach in seinem eigenen Tempo laufen lassen. Versuchen Sie nicht, es zu erzwingen. Konzentrieren Sie sich stattdessen auf eine effiziente Codierung, damit keine Speicherprobleme auftreten (wir werden dies in Schritt 6 behandeln). Schauen wir uns nun noch einmal unsere Beispiel-SWF an und klicken Sie auf die Schaltfläche "Müll sammeln", nachdem Sie ein Objekt erstellt und gelöscht haben.

Haben Sie die Datei getestet? Es funktionierte! Sie können jetzt sehen, dass nach dem Löschen eines Objekts und dem Auslösen des GC das Objekt entfernt wird! Beachten Sie, dass nichts passiert, wenn Sie das Objekt nicht löschen und den GC aufrufen, da der Code noch einen Verweis auf dieses Objekt enthält. Was ist nun, wenn wir versuchen, zwei Verweise auf ein Objekt beizubehalten und einen davon zu entfernen?


Schritt 5: Erstellen einer weiteren Referenz

Nachdem wir bewiesen haben, dass der GC genau so funktioniert, wie wir es wollten, versuchen wir etwas anderes: Verknüpfen Sie einen anderen Verweis mit einem Objekt (Object1) und entfernen Sie das Original. Zuerst müssen wir eine Funktion erstellen, um einen Verweis auf unser Objekt zu verknüpfen und die Verknüpfung aufzuheben. Machen wir das:

Wenn wir unseren SWF jetzt testen, werden wir feststellen, dass nichts passiert, wenn wir Object1 erstellen, dann speichern, löschen und die Ausführung des GC erzwingen. Das liegt daran, dass es jetzt, selbst wenn wir den "ursprünglichen" Link zum Objekt entfernt haben, noch einen weiteren Verweis darauf gibt, der verhindert, dass es für die Speicherbereinigung in Frage kommt. Dies ist im Grunde alles, was Sie über den Garbage Collector wissen müssen. Es ist schließlich kein Rätsel. Aber wie wenden wir dies auf unsere aktuelle Umgebung an? Wie können wir dieses Wissen nutzen, um zu verhindern, dass unsere Anwendung langsam ausgeführt wird? Dies zeigt uns Schritt 6: Wie man dies in realen Beispielen anwendet.


Schritt 6: Machen Sie Ihren Code effizient

Nun zum besten Teil: Damit Ihr Code effizient mit dem GC funktioniert! Dieser Schritt liefert nützliche Informationen, die Sie Ihr ganzes Leben lang aufbewahren sollten - speichern Sie sie ordnungsgemäß! Zunächst möchte ich eine neue Methode zum Erstellen Ihrer Objekte in Ihrer Anwendung vorstellen. Es ist eine einfache, aber effektive Möglichkeit, mit dem GC zusammenzuarbeiten. Auf diese Weise werden zwei einfache Klassen eingeführt, die auf andere erweitert werden können, sobald Sie verstanden haben, was sie tun.

Die Idee auf diese Weise ist, eine Funktion namens destroy() für jedes Objekt zu implementieren, das Sie erstellen, und sie jedes Mal aufzurufen, wenn Sie mit der Arbeit an einem Objekt fertig sind. Die Funktion enthält den gesamten Code, der zum Entfernen aller Verweise auf und von dem Objekt erforderlich ist (mit Ausnahme der Referenz, die zum Aufrufen der Funktion verwendet wurde). Sie stellen also sicher, dass das Objekt Ihre Anwendung vollständig isoliert lässt und vom GC leicht erkannt wird. Der Grund dafür wird im nächsten Schritt erläutert. Schauen wir uns den allgemeinen Code für die Funktion an:

In dieser Funktion müssen Sie alles aus dem Objekt löschen, damit es in der Anwendung isoliert bleibt. Danach ist es für den GC einfacher, das Objekt zu lokalisieren und zu entfernen. Schauen wir uns nun einige Situationen an, in denen die meisten Speicherfehler auftreten:

  • Objekte, die nur in einem Ausführungsintervall verwendet werden: Seien Sie vorsichtig mit diesen, da diese viel Speicher verbrauchen können. Diese Objekte existieren nur für einen bestimmten Zeitraum (z. B. zum Speichern von Werten, wenn eine Funktion ausgeführt wird) und werden nicht sehr häufig aufgerufen. Denken Sie daran, alle Verweise auf sie zu entfernen, nachdem Sie mit ihnen fertig sind. Andernfalls können Sie viele davon in Ihrer Anwendung haben und nur Speicherplatz beanspruchen. Denken Sie daran, dass Sie, wenn Sie viele Verweise darauf erstellen, jeden durch die Funktion destroy() entfernen müssen.
  • In der Anzeigeliste verbleibende Objekte: Entfernen Sie immer ein Objekt aus der Anzeigeliste, wenn Sie es löschen möchten. Die Anzeigeliste ist eine der Wurzeln der Speicherbereinigung (erinnern Sie sich daran?). Daher ist es sehr wichtig, dass Sie Ihre Objekte beim Entfernen davon fernhalten.
  • Stage-, Parent- und Root-Referenzen: Wenn Sie diese Eigenschaften häufig verwenden möchten, denken Sie daran, sie zu entfernen, wenn Sie fertig sind. Wenn viele Ihrer Objekte einen Verweis auf diese haben, können Sie in Schwierigkeiten geraten!
  • Ereignis-Listener: Manchmal ist die Referenz, die verhindert, dass Ihre Objekte erfasst werden, ein Ereignis-Listener. Denken Sie daran, sie zu entfernen oder bei Bedarf als schwache Zuhörer zu verwenden.
  • Arrays und Vektoren: Manchmal können Ihre Arrays und Vektoren andere Objekte enthalten, sodass darin Referenzen verbleiben, die Sie möglicherweise nicht kennen. Seien Sie vorsichtig mit Arrays und Vektoren!

Schritt 7: Die Insel der Referenzen

Obwohl die Arbeit mit dem GC großartig ist, ist sie nicht perfekt. Sie müssen darauf achten, was Sie tun, sonst können mit Ihrer Anwendung schlimme Dinge passieren. Ich möchte ein Problem aufzeigen, das auftreten kann, wenn Sie nicht alle erforderlichen Schritte ausführen, damit Ihr Code ordnungsgemäß mit dem GC funktioniert.

Wenn Sie nicht alle Verweise auf und von einem Objekt löschen, tritt manchmal dieses Problem auf, insbesondere wenn Sie viele Objekte in Ihrer Anwendung miteinander verknüpfen. Manchmal kann eine einzige verbleibende Referenz ausreichen, um dies zu erreichen: Alle Ihre Objekte bilden eine Referenzinsel, auf der alle Objekte mit anderen verbunden sind, sodass der GC sie nicht entfernen kann.

Wenn der GC ausgeführt wird, führt er zwei einfache Aufgaben aus, um nach zu löschenden Objekten zu suchen. Eine dieser Aufgaben besteht darin, zu zählen, wie viele Referenzen jedes Objekt hat. Alle Objekte mit 0 Referenzen werden gleichzeitig gesammelt. Die andere Aufgabe besteht darin, zu überprüfen, ob eine kleine Anzahl von Objekten miteinander verknüpft ist, auf die jedoch nicht zugegriffen werden kann, wodurch Speicherplatz verschwendet wird. Überprüfen Sie das Bild:

Wie Sie sehen können, sind die grünen Objekte nicht erreichbar, aber ihre Referenzzählung ist 1. Der GC führt die zweite Aufgabe aus, um nach diesem Objektblock zu suchen und alle zu entfernen. Wenn der Block jedoch zu groß ist, gibt der GC die Überprüfung auf und geht davon aus, dass die Objekte erreicht werden können. Stellen Sie sich nun vor, Sie hätten so etwas:

Dies ist die Insel der Referenzen. Es würde viel Speicher vom System beanspruchen und vom GC aufgrund seiner Komplexität nicht erfasst werden. Es klingt ziemlich schlecht, oder? Es kann jedoch leicht vermieden werden. Stellen Sie einfach sicher, dass Sie alle Verweise auf und von einem Objekt gelöscht haben, und dann passieren solche beängstigenden Dinge nicht!


Schlussfolgerung

Das ist es für jetzt. In diesem kurzen Tipp haben wir gelernt, dass wir unseren Code besser und effizienter machen können, um Verzögerungs- und Speicherprobleme zu reduzieren und ihn so stabiler zu machen. Dazu müssen wir verstehen, wie Referenzierungsobjekte in AS3 funktionieren und wie Sie davon profitieren können, damit der GC in unserer Anwendung ordnungsgemäß funktioniert. Trotz der Tatsache, dass wir unsere Anwendung verbessern können, müssen wir dabei vorsichtig sein - sonst kann es noch unordentlicher und langsamer werden!

Ich hoffe hat Ihnen dieser einfache Tipp gefallen. Wenn Sie Fragen haben, schreiben Sie unten einen Kommentar!

Advertisement
Did you find this post useful?
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.