javascript how jQuery Speicherleckmuster und Ursachen




javascript memory game (2)

Was sind einige der Standardprobleme oder Codierungsmuster in jQuery, die zu Speicherlecks führen?

Ich habe eine Reihe von Fragen im Zusammenhang mit dem Aufruf von ajax () oder jsonp oder DOM auf StackOverflow gesehen. Die meisten jQuery-Memory-Leak-Fragen konzentrieren sich auf bestimmte Probleme oder Browser und es wäre schön, eine Auflistung der Standardspeicherleckmuster in jQuery zu haben.

Hier sind einige verwandte Fragen zu SO:

Ressourcen im Internet:


Answer #1

Soweit ich weiß, wird die Speicherverwaltung in JavaScript durch Referenzzählung ausgeführt. Während eine Referenz auf ein Objekt noch existiert, wird die Zuordnung nicht aufgehoben. Dies bedeutet, dass das Erstellen eines Speicherlecks in einer Anwendung mit einer einzelnen Seite trivial ist und Benutzer, die von einem Java-Hintergrund kommen, überstürzen kann. Dies ist nicht spezifisch für JQuery. Nehmen Sie den folgenden Code zum Beispiel:

function MyObject = function(){
   var _this = this;
   this.count = 0;
   this.getAndIncrement = function(){
       _this.count++;
       return _this.count;
   }
}

for(var i = 0; i < 10000; i++){
    var obj = new MyObject();
    obj.getAndIncrement();
}

Es wird normal aussehen, bis Sie sich die Speichernutzung ansehen. Instanzen von MyObject werden nie freigegeben, während die Seite aktiv ist, aufgrund des "_this" -Zeigers (erhöhen Sie den Maximalwert von i, um ihn dramatischer zu sehen.). (In älteren Versionen von IE wurden sie nie freigegeben, bis das Programm beendet wird.) Da JavaScript-Objekte zwischen Frames geteilt werden können (ich empfehle das nicht, da es ernsthaft temperamentvoll ist), gibt es Fälle, in denen sogar in einem modernen Browser Javascript ist Gegenstände können viel länger herumhängen als sie gedacht sind.

Im Kontext von jQuery werden häufig Referenzen gespeichert, um den Overhead der Domänensuche zu sparen. Beispiel:

function run(){
    var domObjects = $(".myClass");
    domObjects.click(function(){
        domObjects.addClass(".myOtherClass");
    });
}

Dieser Code behält domObject (und seinen gesamten Inhalt) wegen des Verweises in der Callback-Funktion für immer.

Wenn die Writer von jquery intern solche Instanzen verpasst haben, wird die Bibliothek selbst undicht, aber häufiger ist es der Client-Code.

Das zweite Beispiel kann behoben werden, indem der Zeiger explizit gelöscht wird, wenn er nicht mehr benötigt wird:

function run(){
    var domObjects = $(".myClass");
    domObjects.click(function(){
        if(domObjects){
            domObjects.addClass(".myOtherClass");
            domObjects = null;
        }
    });
}

oder die Suche erneut durchführen:

function run(){
    $(".myClass").click(function(){
        $(".myClass").addClass(".myOtherClass");
    });
}

Eine gute Faustregel ist, dass Sie vorsichtig sein sollten, wo Sie Ihre Callback-Funktionen definieren, und möglichst zu viel Verschachtelung vermeiden.

Edit: Wie in den Kommentaren von Erik gezeigt wurde, könnten Sie auch den this -Zeiger verwenden, um die unnötige dom-Suche zu vermeiden:

function run(){
    $(".myClass").click(function(){
        $(this).addClass(".myOtherClass");
    });
}

Answer #2

Ich werde hier ein Anti-Muster beisteuern, welches das "Mid-Chain-Reference" -Leck ist.

Eine der Stärken von jQuery ist die Chaining-API, mit der Sie die Elemente weiterhin ändern, filtern und bearbeiten können:

$(".message").addClass("unread").find(".author").addClass("noob");

Am Ende dieser Kette haben Sie ein jQuery-Objekt mit allen ".message .author" -Elementen, aber dieses Objekt verweist auf die ursprünglichen ".message" -Elemente und Objekt mit ihnen. Sie können über die Methode .end() zu ihnen gelangen und etwas für sie tun:

 $(".message")
   .find(".author")
     .addClass("prolific")
   .end()
   .addClass("unread");

Jetzt, wenn es auf diese Weise verwendet wird, gibt es keine Probleme mit Lecks. Wenn Sie jedoch das Ergebnis einer Kette einer Variablen zuweisen, die eine lange Lebensdauer hat, bleiben die Rückverweise auf frühere Sätze erhalten, und es kann keine Garbage Collection durchgeführt werden, bis die Variable den Gültigkeitsbereich verlässt. Wenn diese Variable global ist, gehen die Referenzen niemals außerhalb des Gültigkeitsbereichs.

Nehmen wir zum Beispiel an, dass Sie 2008 in einem Blogbeitrag gelesen haben, dass $("a").find("b") "effizienter" ist als $("ab") (obwohl es nicht angemessen ist, darüber nachzudenken) eine Mikro-Optimierung). Sie entscheiden, dass Sie eine seitenweite globale Liste mit Autoren benötigen, damit Sie Folgendes tun:

authors = $(".message").find(".author");

Jetzt haben Sie ein jQuery-Objekt mit der Liste der Autoren, aber es verweist auch auf ein jQuery-Objekt, das die vollständige Liste der Nachrichten darstellt. Du wirst es wahrscheinlich nie benutzen oder wissen, dass es da ist und es nimmt Speicher auf.

Beachten Sie, dass Lecks nur mit den Methoden auftreten können, die neue Elemente aus einer vorhandenen Menge auswählen, z. B. .find , .filter , .children usw. Die Dokumente geben an, wann eine neue Menge zurückgegeben wird. Die einfache Verwendung einer Verkettungs-API verursacht kein Leck, wenn die Kette einfache nicht-filternde Methoden wie .css . Dies ist also in Ordnung:

authors = $(".message .author").addClass("prolific");




garbage-collection