2015-09-30 3 views
6

Ich lese diesen Artikel (http://javascript.info/tutorial/memory-leaks#memory-leak-size) über Speicherlecks, die dies als ein Speicherleck erwähnt:Müssen wir manuell nicht referenzierte Variablen in einem Abschluss bereinigen?

function f() { 
    var data = "Large piece of data"; 

    function inner() { 
     return "Foo"; 
    } 

    return inner; 
} 

JavaScript-Interpreter keine Ahnung hat, welche Variablen von die innere Funktion erforderlich sein kann, so dass es hält alles. In jeder äußeren LexicalEnvironment. Ich hoffe, neuere Dolmetscher versuchen, es zu optimieren, aber nicht sicher über ihren Erfolg.

Der Artikel schlägt vor, dass wir data = null manuell setzen müssen, bevor wir die innere Funktion zurückgeben.

Stimmt das heute? Oder ist dieser Artikel veraltet? (Wenn es veraltet ist, kann mich jemand auf eine Ressource über aktuelle Fallstricke hinweisen)

Antwort

5

Moderne Engines würden nicht verwendete Variablen im äußeren Bereich beibehalten.

Daher spielt es keine Rolle, ob Sie data = null einstellen, bevor die innere Funktion zurückkehrt, weil die innere Funktion nicht davon abhängt („schließen over“) data.

Wenn die innere Funktion auf data abhing --perhaps es sie gibt - dann Einstellung data = null ist sicherlich nicht, was Sie wollen, weil dann, na ja, wäre es null sein, anstatt den ursprünglichen Wert des Habens !

die innere Funktion Unter der Annahme, auf data abhängt, dann ja, solange inner zu (nach) etwas hingewiesen wird, dann wird der Wert von data wird um gehalten werden muß. Aber das sagst du, was du willst! Wie können Sie etwas verfügbar haben, ohne es verfügbar zu haben?

Denken Sie daran, dass die Variable, die den Rückgabewert von f() enthält, an einem bestimmten Punkt nicht mehr in den Gültigkeitsbereich fällt. An diesem Punkt, mindestens bis f() wird erneut aufgerufen, data wird Müll gesammelt werden.

Die allgemeine Regel ist, dass Sie sich keine Gedanken über Speicher und Lecks mit JavaScript machen müssen. Das ist der springende Punkt von GC. Der Müllsammler leistet eine hervorragende Arbeit, um zu identifizieren, was benötigt wird und was nicht benötigt wird, und den Müllsammler zu behalten, der letzteres sammelt.

Sie können das folgende Beispiel in Betracht ziehen:

function foo() { 
    var x = 1; 
    return function() { debugger; return 1; }; 
} 

function bar() { 
    var x = 1; 
    return function() { debugger; return x; }; 
} 

foo()(); 
bar()(); 

Und seine Ausführung untersuchen in Chrome variable Fenster DevTools. Wenn der Debugger in der inneren Funktion von foo stoppt, beachten Sie, dass x nicht als eine lokale Variable oder als eine Schließung vorhanden ist. Für alle praktischen Zwecke existiert es nicht.

Wenn der Debugger in der inneren Funktion von bar stoppt, sehen wir die Variable x, weil es beibehalten werden musste, um zugänglich zu sein, um zurückgegeben zu werden.

Stimmt das heute? Oder ist dieser Artikel veraltet?

Nein, tut es nicht, und ja, ist es. Der Artikel ist vier Jahre alt, was ein Leben lang in der Webwelt ist. Ich habe keine Möglichkeit zu wissen, ob jQuery noch immer undicht ist, aber ich wäre überrascht, wenn es so wäre, und wenn ja, gibt es einen einfachen Weg, sie zu vermeiden - benutze jQuery nicht. Die Lecks, die der Autor des Artikels in Bezug auf DOM-Schleifen und Event-Handler erwähnt, sind in modernen Browsern nicht vorhanden, mit denen ich IE10 (wahrscheinlicher IE9) und höher meine. Ich würde vorschlagen, eine aktuellere Referenz zu finden, wenn Sie wirklich über Speicherlecks verstehen wollen. Eigentlich würde ich vorschlagen, dass Sie hauptsächlich aufhören, sich über Speicherlecks Sorgen zu machen. Sie treten nur in sehr speziellen Situationen auf. Aus diesem Grund ist es heutzutage schwierig, viel zu diesem Thema im Internet zu finden. Hier ist ein Artikel, den ich gefunden habe: http://point.davidglasser.net/2013/06/27/surprising-javascript-memory-leak.html.

+0

Dank Torazaburo. Was mich beunruhigt, ist, dass der letzte Ausschnitt in dem Artikel, den Sie über den Meteor-Fehler zur Verfügung gestellt haben, tatsächlich Speicher in V8 verliert. – Jonathan

+0

"Eigentlich würde ich vorschlagen, dass Sie hauptsächlich aufhören, sich Gedanken über Speicherlecks zu machen. Sie treten nur in sehr speziellen Situationen auf." Ich stimme dieser Aussage nicht zu. Zumindest Detached DOMs treten häufig in SPAs auf und jeder Entwickler muss darüber Bescheid wissen. –

1

Zusätzlich zu @torazaburos exzellenter Antwort ist es wichtig, darauf hinzuweisen, dass die Beispiele in diesem Tutorial keine Lecks sind. Ein Leck, was passiert, wenn ein Programm einen Verweis auf etwas löscht, aber nicht den Speicher freigibt, den es verbraucht.

Das letzte Mal erinnere ich mich, dass JS-Entwickler wirklich über echte Lecks besorgt waren, als Internet Explorer (6 und 7 glaube ich) getrennte Speicherverwaltung für das DOM und für JS verwendet. Aus diesem Grund war es möglich, ein onclick Ereignis an eine Schaltfläche zu binden, die Schaltfläche zu zerstören und den Ereignishandler immer im Speicher zu lassen - für immer (oder bis der Browser abstürzte oder vom Benutzer geschlossen wurde). Sie konnten den Handler nicht auslösen oder ihn nach der Tat freigeben. Es saß einfach auf dem Stapel und nahm Platz. Wenn Sie also eine langlebige Webanwendung oder eine Webseite hatten, die viele DOM-Elemente erzeugte und zerstörte, mussten Sie extrem fleißig sein, um Ereignisse immer zu lösen, bevor Sie sie löschten.

Ich habe auch in ein paar lästige Lecks in iOS gerannt, aber das waren alle Bugs und wurden (schließlich) von Apple gepatcht.

Das heißt, ein guter Entwickler muss Ressourcenverwaltung beim Schreiben von Code berücksichtigen. Betrachten Sie diese zwei Konstrukteure:

function F() { 
    var data = "One megabyte of data"; 

    this.inner = new function() { 
     return data; 
    } 
} 

var G = function() {}; 
G.prototype.data = "One megabyte of data"; 
G.prototype.inner = function() { 
    return this.data; 
}; 

Wenn Sie mehr als tausend Fälle von F zu schaffen, würde der Browser für alle, die Kopien der großen Zeichenfolge ein zusätzliches Gigabyte Speicher zuweisen müssen. Und jedes Mal, wenn du eine Instanz löschst, wirst du auf dem Bildschirm Bildschirmwackeln bekommen, wenn der GC den Rammbock schließlich wiedererlangt hat. Auf der anderen Seite, wenn Sie tausend Instanzen von G erstellt haben, würde die riesige Zeichenfolge einmal erstellt und von jeder Instanz wiederverwendet werden. Das ist ein enormer Leistungsschub.

Aber der Vorteil von F ist, dass die riesige Zeichenfolge im Wesentlichen privat ist. Kein anderer Code außerhalb des Konstruktors könnte direkt auf diese Zeichenfolge zugreifen. Aus diesem Grund könnte jede Instanz von F diese Zeichenfolge so oft ändern, wie sie wollte, und Sie müssen sich nie darum kümmern, dass andere Instanzen Probleme verursachen.

Auf der anderen Seite ist die riesige Zeichenfolge in G da draußen für jeden zu ändern. Andere Instanzen könnten dies ändern, und jeder Code, der denselben Bereich wie G hat, könnte dies ebenfalls tun.

In diesem Fall besteht also ein Kompromiss zwischen Ressourcennutzung und Sicherheit.

+0

Gut zu erwähnen, dass dem Prototyp gemeinsame Daten hinzugefügt werden.Ich werde hier auch einen Link auf [diese Frage über zirkuläre Referenzen in js] (http://stackoverflow.com/q/7347203/2407212) setzen, da dies auch auf allgemeine Überzeugungen bezüglich Speicherlecks bezieht. – Jonathan

Verwandte Themen