Was ist JavaScript-Speicherbereinigung? Was ist für einen Webprogrammierer wichtig, um die JavaScript-Speicherbereinigung zu verstehen, um besseren Code schreiben zu können?
Was ist JavaScript-Speicherbereinigung? Was ist für einen Webprogrammierer wichtig, um die JavaScript-Speicherbereinigung zu verstehen, um besseren Code schreiben zu können?
Antworten:
Eric Lippert hat vor einiger Zeit einen ausführlichen Blog-Beitrag zu diesem Thema geschrieben (zusätzlich zu VBScript ). Genauer gesagt schrieb er über JScript , die Microsoft-eigene Implementierung von ECMAScript, obwohl sie JavaScript sehr ähnlich ist. Ich würde mir vorstellen, dass Sie davon ausgehen können, dass die überwiegende Mehrheit des Verhaltens für die JavaScript-Engine von Internet Explorer gleich ist. Natürlich wird die Implementierung von Browser zu Browser unterschiedlich sein, obwohl ich vermute, dass Sie eine Reihe der gemeinsamen Prinzipien auf andere Browser anwenden können.
Zitiert von dieser Seite:
JScript verwendet einen nicht generationenübergreifenden Mark-and-Sweep-Garbage-Collector. Es funktioniert so:
Jede Variable, die "im Gültigkeitsbereich" ist, wird als "Scavenger" bezeichnet. Ein Aasfresser kann sich auf eine Zahl, ein Objekt, eine Zeichenfolge usw. beziehen. Wir führen eine Liste von Scavengern - Variablen werden in die Scav-Liste verschoben, wenn sie in den Gültigkeitsbereich gelangen, und aus der Scav-Liste entfernt, wenn sie den Gültigkeitsbereich verlassen.
Hin und wieder läuft der Müllsammler. Zuerst wird jedes Objekt, jede Variable, jede Zeichenfolge usw. markiert - der gesamte vom GC verfolgte Speicher. (JScript verwendet die VARIANT-Datenstruktur intern und es gibt viele zusätzliche nicht verwendete Bits in dieser Struktur, daher setzen wir nur eines davon.)
Zweitens werden die Markierungen auf den Aasfressern und das vorübergehende Schließen von Aasfresserreferenzen gelöscht. Wenn also ein Scavenger-Objekt auf ein Nicht-Scavenger-Objekt verweist, löschen wir die Bits auf dem Nicht-Scavenger und auf allem, worauf es sich bezieht. (Ich verwende das Wort "Schließung" in einem anderen Sinne als in meinem früheren Beitrag.)
Zu diesem Zeitpunkt wissen wir, dass dem gesamten noch markierten Speicher Speicher zugewiesen ist, der von keinem Pfad aus einer In-Scope-Variablen erreicht werden kann. Alle diese Objekte werden angewiesen, sich selbst abzureißen, wodurch alle Zirkelverweise zerstört werden.
Der Hauptzweck der Speicherbereinigung besteht darin, dem Programmierer zu ermöglichen, sich keine Gedanken über die Speicherverwaltung der von ihm erstellten und verwendeten Objekte zu machen, obwohl dies natürlich manchmal nicht zu vermeiden ist. Es ist immer von Vorteil, zumindest eine ungefähre Vorstellung davon zu haben, wie die Speicherbereinigung funktioniert .
Historischer Hinweis: Eine frühere Überarbeitung der Antwort hatte einen falschen Verweis auf den delete
Bediener. In JavaScript entfernt der delete
Operator eine Eigenschaft aus einem Objekt und unterscheidet sich grundlegend von delete
C / C ++.
delete
falsch. Beispiel: Im ersten Beispiel sollten Sie stattdessen delete foo
zuerst den Ereignis-Listener über entfernen window.removeEventListener()
und dann foo = null
die Variable überschreiben. im IE hätte delete window.foo
(aber nicht delete foo
) auch funktioniert, wenn foo
es global gewesen wäre, aber selbst dann würde es nicht in FF oder Opera funktionieren
delete
ist ein unärer Operator (ein Ausdruck), keine Anweisung (dh :) delete 0, delete 0, delete 3
. Es sieht aus wie eine Anweisung, wenn sie durch eine Ausdrucksanweisung ausgedrückt wird.
Achten Sie auf Zirkelverweise, wenn es sich um DOM-Objekte handelt:
Speicherverlustmuster in JavaScript
Beachten Sie, dass der Speicher nur wiederhergestellt werden kann, wenn keine aktiven Verweise auf das Objekt vorhanden sind. Dies ist eine häufige Gefahr bei Schließungen und Ereignishandlern, da einige JS-Engines nicht prüfen, auf welche Variablen in inneren Funktionen tatsächlich verwiesen wird, sondern nur alle lokalen Variablen der umschließenden Funktionen beibehalten.
Hier ist ein einfaches Beispiel:
function init() {
var bigString = new Array(1000).join('xxx');
var foo = document.getElementById('foo');
foo.onclick = function() {
// this might create a closure over `bigString`,
// even if `bigString` isn't referenced anywhere!
};
}
Eine naive JS-Implementierung kann nicht erfasst werden, bigString
solange der Ereignishandler verfügbar ist. Es gibt verschiedene Möglichkeiten, um dieses Problem zu lösen, z. B. die Einstellung bigString = null
am Ende von init()
( delete
funktioniert nicht für lokale Variablen und Funktionsargumente: delete
Entfernt Eigenschaften von Objekten, und auf das Variablenobjekt kann nicht zugegriffen werden - ES5 im strengen Modus löst sogar ein aus, ReferenceError
wenn Sie es versuchen um eine lokale Variable zu löschen!).
Ich empfehle, unnötige Schließungen so weit wie möglich zu vermeiden, wenn Sie den Speicherverbrauch berücksichtigen.
Gutes Zitat aus einem Blog
Die DOM-Komponente ist "Garbage Collected", ebenso wie die JScript-Komponente. Wenn Sie also ein Objekt in einer der Komponenten erstellen und dann den Überblick über dieses Objekt verlieren, wird es schließlich bereinigt.
Zum Beispiel:
function makeABigObject() {
var bigArray = new Array(20000);
}
Wenn Sie diese Funktion aufrufen, erstellt die JScript-Komponente ein Objekt (mit dem Namen bigArray), auf das innerhalb der Funktion zugegriffen werden kann. Sobald die Funktion jedoch zurückkehrt, verlieren Sie den Überblick über bigArray, da es keine Möglichkeit mehr gibt, darauf zu verweisen. Nun, die JScript-Komponente erkennt, dass Sie den Überblick verloren haben, und so wird bigArray bereinigt - sein Speicher wird zurückgefordert. Das Gleiche funktioniert in der DOM-Komponente. Wenn Sie sagen document.createElement('div')
oder etwas Ähnliches, erstellt die DOM-Komponente ein Objekt für Sie. Sobald Sie den Überblick über dieses Objekt verlieren, bereinigt die DOM-Komponente das zugehörige Objekt.
Nach meinem besten Wissen werden die Objekte von JavaScript regelmäßig mit Müll gesammelt, wenn keine Verweise mehr auf das Objekt vorhanden sind. Dies geschieht automatisch, aber wenn Sie mehr über die Funktionsweise auf C ++ - Ebene erfahren möchten, ist es sinnvoll, sich den WebKit- oder V8-Quellcode anzusehen
Normalerweise müssen Sie jedoch nicht darüber nachdenken. In älteren Browsern wie IE 5.5 und früheren Versionen von IE 6 und möglicherweise aktuellen Versionen führen Schließungen jedoch zu Zirkelverweisen, die, wenn sie nicht aktiviert sind, Speicherplatz verbrauchen. In dem speziellen Fall, den ich mit Schließungen meine, haben Sie einen JavaScript-Verweis auf ein Dom-Objekt und ein Objekt auf ein DOM-Objekt hinzugefügt, das auf das JavaScript-Objekt zurückgeht. Grundsätzlich könnte es niemals gesammelt werden und würde schließlich dazu führen, dass das Betriebssystem in Test-Apps instabil wird, die Schleifen bilden, um Abstürze zu verursachen. In der Praxis sind diese Lecks normalerweise klein, aber um Ihren Code sauber zu halten, sollten Sie den JavaScript-Verweis auf das DOM-Objekt löschen.
Normalerweise ist es eine gute Idee, das Schlüsselwort delete zu verwenden, um große Objekte wie JSON-Daten, die Sie zurückerhalten haben, sofort zu de-referenzieren und alles zu tun, was Sie damit tun müssen, insbesondere in der mobilen Webentwicklung. Dies bewirkt, dass der nächste Durchlauf des GC dieses Objekt entfernt und seinen Speicher freigibt.
mark-and-sweep
Algorithmen sorgen dafür .
Garbage Collection (GC) ist eine Form der automatischen Speicherverwaltung, bei der nicht mehr benötigte Objekte entfernt werden.
Jeder Prozess, der sich mit dem Speicher befasst, führt die folgenden Schritte aus:
1 - Weisen Sie Ihren benötigten Speicherplatz zu
2 - etwas verarbeiten
3 - Geben Sie diesen Speicherplatz frei
Es gibt zwei Hauptalgorithmen, mit denen erkannt wird, welche Objekte nicht mehr benötigt werden.
Garbage Collection mit Referenzzählung : Dieser Algorithmus reduziert die Definition von "ein Objekt wird nicht mehr benötigt" auf "ein Objekt hat kein anderes Objekt, das darauf verweist". Das Objekt wird entfernt, wenn kein Referenzpunkt darauf vorhanden ist
Mark-and-Sweep-Algorithmus : Verbinden Sie jedes Objekt mit der Root-Quelle. Jedes Objekt stellt keine Verbindung zu root oder einem anderen Objekt her. Dieses Objekt wird entfernt.
Derzeit verwenden die meisten modernen Browser den zweiten Algorithmus.
"In der Informatik ist Garbage Collection (GC) eine Form der automatischen Speicherverwaltung. Der Garbage Collector oder nur der Collector versucht, Müll oder Speicher zurückzugewinnen, der von Objekten verwendet wird, auf die die Anwendung nie wieder zugreifen oder die sie mutieren werden."
Alle JavaScript-Engines haben ihre eigenen Garbage Collectors und können sich unterscheiden. Meistens muss man sich nicht mit ihnen befassen, weil sie einfach das tun, was sie tun sollen.
Das Schreiben von besserem Code hängt hauptsächlich davon ab, wie gut Sie die Programmierprinzipien, die Sprache und die jeweilige Implementierung kennen.
Was ist JavaScript-Speicherbereinigung?
Überprüfen Sie dies
Was ist für einen Webprogrammierer wichtig, um die JavaScript-Speicherbereinigung zu verstehen, um besseren Code schreiben zu können?
In Javascript interessiert Sie die Speicherzuweisung und Freigabe nicht. Das ganze Problem wird vom Javascript-Interpreter verlangt. Lecks sind in Javascript immer noch möglich, aber sie sind Fehler des Interpreters. Wenn Sie sich für dieses Thema interessieren, können Sie mehr unter www.memorymanagement.org lesen
Unter Windows können Sie Drip.exe verwenden , um Speicherlecks zu finden oder um zu überprüfen, ob Ihre kostenlose Mem-Routine funktioniert.
Es ist ganz einfach, geben Sie einfach eine Website-URL ein und Sie sehen den Speicherverbrauch des integrierten IE-Renderers. Klicken Sie dann auf Aktualisieren. Wenn sich der Speicher vergrößert, haben Sie irgendwo auf der Webseite einen Speicherverlust festgestellt. Dies ist jedoch auch sehr nützlich, um festzustellen, ob Routinen zum Freigeben von Speicher für den Internet Explorer funktionieren.
Referenztypen speichern das Objekt nicht direkt in der Variablen, der es zugewiesen ist, sodass die Objektvariable in diesem Beispiel die Objektinstanz nicht enthält. Stattdessen enthält es einen Zeiger (oder eine Referenz) auf die Stelle im Speicher, an der das Objekt vorhanden ist
var object = new Object();
Wenn Sie eine Variable einer anderen zuweisen, erhält jede Variable eine Kopie des Zeigers, und beide verweisen immer noch auf dasselbe Objekt im Speicher.
var object1 = new Object();
var object2 = object1;
JavaScript ist eine durch Müll gesammelte Sprache, sodass Sie sich bei der Verwendung von Referenztypen keine Gedanken über die Speicherzuweisung machen müssen. Es ist jedoch am besten, nicht mehr benötigte Objekte zu dereferenzieren , damit der Garbage Collector diesen Speicher freigeben kann. Der beste Weg, dies zu tun, besteht darin, die Objektvariable auf null zu setzen.
var object1 = new Object();
// do something
object1 = null; // dereference
Das Dereferenzieren von Objekten ist besonders wichtig in sehr großen Anwendungen, die Millionen von Objekten verwenden.
aus den Prinzipien des objektorientierten JavaScript - NICHOLAS C. ZAKAS