wake-up-neo.com

Mit Chrome

Ich habe einen sehr einfachen Testfall erstellt, der eine Backbone-Ansicht erstellt, einen Handler an ein Ereignis anfügt und eine benutzerdefinierte Klasse instanziiert. Ich glaube, dass durch Klicken auf die Schaltfläche "Entfernen" in diesem Beispiel alles bereinigt wird und es keine Speicherlecks geben sollte.

Eine Jsfiddle für den Code ist hier: http://jsfiddle.net/4QhR2/

// scope everything to a function
function main() {

    function MyWrapper() {
        this.element = null;
    }
    MyWrapper.prototype.set = function(elem) {
        this.element = elem;
    }
    MyWrapper.prototype.get = function() {
        return this.element;
    }

    var MyView = Backbone.View.extend({
        tagName : "div",
        id : "view",
        events : {
            "click #button" : "onButton",
        },    
        initialize : function(options) {        
            // done for demo purposes only, should be using templates
            this.html_text = "<input type='text' id='textbox' /><button id='button'>Remove</button>";        
            this.listenTo(this,"all",function(){console.log("Event: "+arguments[0]);});
        },
        render : function() {        
            this.$el.html(this.html_text);

            this.wrapper = new MyWrapper();
            this.wrapper.set(this.$("#textbox"));
            this.wrapper.get().val("placeholder");

            return this;
        },
        onButton : function() {
            // assume this gets .remove() called on subviews (if they existed)
            this.trigger("cleanup");
            this.remove();
        }
    });

    var view = new MyView();
    $("#content").append(view.render().el);
}

main();

Ich bin mir jedoch nicht sicher, wie ich den Profiler von Google Chrome verwenden soll, um zu überprüfen, ob dies tatsächlich der Fall ist. Es gibt eine Unmenge von Dingen, die in der Momentaufnahme des Heap-Profilers auftauchen, und ich habe keine Ahnung, wie ich entschlüsseln kann, was gut/schlecht ist. In den Tutorials, die ich bisher gesehen habe, soll ich entweder nur "den Snapshot-Profiler verwenden" oder mir ein äußerst detailliertes Manifest über die Funktionsweise des gesamten Profilers geben. Ist es möglich, den Profiler nur als Werkzeug zu verwenden, oder muss ich wirklich verstehen, wie das Ganze entwickelt wurde?

EDIT: Tutorials wie diese:

Fehlerbehebung bei Google Mail-Speicherverlusten

mit DevTools

Sind repräsentativ für einige der stärkeren Materialien da draußen, von dem, was ich gesehen habe. Abgesehen von der Einführung des Konzepts der 3 Schnappschuss-Technik finde ich jedoch, dass sie nur sehr wenig praktisches Wissen bieten (für Anfänger wie mich). Das Tutorial 'Using DevTools' arbeitet nicht an einem realen Beispiel, daher ist seine vage und allgemeine konzeptionelle Beschreibung der Dinge nicht besonders hilfreich. Zum Beispiel "Google Mail":

Sie haben also ein Leck gefunden. Was nun?

  • Untersuchen Sie den Haltepfad von durchgesickerten Objekten in der unteren Hälfte des Profilbedienfelds

  • Wenn die Zuweisungsstelle nicht einfach abgeleitet werden kann (d. H. Ereignis-Listener):

  • Instrumentieren Sie den Konstruktor des Aufbewahrungsobjekts über die JS-Konsole, um den Stack-Trace für Zuweisungen zu speichern

  • Closure verwenden? Aktivieren Sie das entsprechende vorhandene Flag (d. H. Goog.events.Listener.ENABLE_MONITORING), um die Eigenschaft creationStack während der Erstellung festzulegen

Nachdem ich das gelesen habe, bin ich mehr verwirrt, nicht weniger. Und noch einmal, es fordert mich nur auf, wie Dinge zu tun, nicht wie sie zu tun. Aus meiner Sicht sind alle Informationen entweder zu vage oder nur für jemanden sinnvoll, der den Prozess bereits verstanden hat.

Einige dieser spezifischeren Probleme wurden in @ Jonathan Naguins Antwort unten angesprochen.

157
EleventyOne

Ein guter Workflow zum Auffinden von Speicherlecks ist die Drei-Momentaufnahmen-Technik , mit der Loreena Lee und das Google Mail-Team zunächst einige ihrer Speicherprobleme lösen. Die Schritte sind im Allgemeinen:

  • Machen Sie einen Haufen Schnappschuss.
  • Sachen machen.
  • Machen Sie einen weiteren Haufen-Schnappschuss.
  • Wiederholen Sie das gleiche Zeug.
  • Machen Sie einen weiteren Haufen-Schnappschuss.
  • Filtern Sie Objekte, die in der Ansicht "Zusammenfassung" von Snapshot 3 zwischen Snapshot 1 und 2 zugeordnet sind.

Für Ihr Beispiel habe ich den Code angepasst, um diesen Prozess zu zeigen (Sie finden ihn hier ) und die Erstellung der Backbone-Ansicht bis zum Klickereignis der Schaltfläche Start zu verzögern. Jetzt:

  • Führen Sie den HTML-Code aus (lokal gespeichert unter Verwendung dieser Adresse ) und machen Sie einen Schnappschuss.
  • Klicken Sie auf Start, um die Ansicht zu erstellen.
  • Machen Sie einen weiteren Schnappschuss.
  • Klicken Sie auf Entfernen.
  • Machen Sie einen weiteren Schnappschuss.
  • Filtern Sie Objekte, die in der Ansicht "Zusammenfassung" von Snapshot 3 zwischen Snapshot 1 und 2 zugeordnet sind.

Jetzt sind Sie bereit, Speicherlecks zu finden!

Sie werden Knoten mit verschiedenen Farben bemerken. Rote Knoten haben keine direkten Verweise von Javascript auf sie, leben aber, weil sie Teil eines getrennten DOM-Baums sind. Es kann einen Knoten in der Struktur geben, auf den von Javascript verwiesen wird (möglicherweise als ein Abschluss oder eine Variable), der jedoch zufällig verhindert, dass die gesamte DOM-Struktur mit Müll zusammengetragen wird.

enter image description here

Gelbe Knoten haben jedoch direkte Referenzen von Javascript. Suchen Sie nach gelben Knoten in derselben getrennten DOM-Struktur, um Referenzen in Ihrem Javascript zu finden. Es sollte eine Reihe von Eigenschaften geben, die vom DOM-Fenster zum Element führen.

In Ihrem speziellen können Sie ein HTML Div-Element sehen, das als rot markiert ist. Wenn Sie das Element erweitern, sehen Sie, dass es von einer "Cache" -Funktion referenziert wird.

enter image description here

Wählen Sie die Zeile aus und geben Sie in Ihrer Konsole $ 0 ein, um die aktuelle Funktion und Position anzuzeigen:

>$0
function cache( key, value ) {
        // Use (key + " ") to avoid collision with native prototype properties (see Issue #157)
        if ( keys.Push( key += " " ) > Expr.cacheLength ) {
            // Only keep the most recent entries
            delete cache[ keys.shift() ];
        }
        return (cache[ key ] = value);
    }                                                     jquery-2.0.2.js:1166

Hier wird auf Ihr Element verwiesen. Leider können Sie nicht viel tun, es handelt sich um einen internen Mechanismus von jQuery. Aber, nur zu Testzwecken, gehen Sie die Funktion und ändern Sie die Methode zu:

function cache( key, value ) {
    return value;
}

Wenn Sie nun den Vorgang wiederholen, sehen Sie keinen roten Knoten :)

Dokumentation:

195
Jonathan Naguin

Hier ist ein Tipp zur Speicherprofilerstellung für eine jsfiddle: Verwenden Sie die folgende URL, um Ihr jsfiddle-Ergebnis zu isolieren. Dabei wird das gesamte jsfiddle-Framework entfernt und nur Ihr Ergebnis geladen.

http://jsfiddle.net/4QhR2/show/

Ich konnte nie herausfinden, wie ich mithilfe der Zeitleiste und des Profilers Speicherlecks aufspüren kann, bis ich die folgende Dokumentation gelesen habe. Nachdem ich den Abschnitt mit dem Titel "Objektzuweisungs-Tracker" gelesen hatte, konnte ich das Tool "Heapzuweisungen aufzeichnen" verwenden und einige abgetrennte DOM-Knoten verfolgen.

Ich habe das Problem behoben, indem ich von der jQuery-Ereignisbindung zur Verwendung der Backbone-Ereignisdelegierung gewechselt bin. Es ist mein Verständnis, dass neuere Versionen von Backbone die Ereignisse automatisch für Sie aufheben, wenn Sie View.remove() aufrufen. Führen Sie einige der Demos selbst aus. Sie sind mit Speicherlecks ausgestattet, die Sie identifizieren können. Sie können hier gerne Fragen stellen, wenn Sie diese nach dem Lesen dieser Dokumentation immer noch nicht erhalten.

https://developers.google.com/chrome-developer-tools/docs/javascript-memory-profiling

7
ricksuggs

Grundsätzlich müssen Sie die Anzahl der Objekte in Ihrem Heap-Snapshot überprüfen. Wenn sich die Anzahl der Objekte zwischen zwei Schnappschüssen erhöht und Sie Objekte entsorgt haben, liegt ein Speicherverlust vor. Mein Rat ist, nach Ereignishandlern in Ihrem Code zu suchen, die nicht getrennt werden.

6

Es gibt ein Einführungsvideo von Google, das sehr hilfreich sein wird, um JavaScript-Speicherlecks zu finden.

https://www.youtube.com/watch?v=L3ugr9BJqIs

4
令狐葱

Sie können auch die Registerkarte Zeitachse in den Entwicklertools aufrufen. Zeichnen Sie die Nutzung Ihrer App auf und behalten Sie die Anzahl der DOM Node und Event Listener im Auge.

Wenn das Speicherdiagramm tatsächlich einen Speicherverlust anzeigt, können Sie den Profiler verwenden, um herauszufinden, was undicht ist.

3
Robert Falkén

Vielleicht möchten Sie auch lesen:

http://addyosmani.com/blog/taming-the-Unicorn-easing-javascript-memory-profiling-in-devtools/

Es wird die Verwendung der chrome Entwicklertools erläutert und es werden einige schrittweise Anleitungen zum Bestätigen und Lokalisieren eines Speicherverlusts mithilfe des Heap-Snapshot-Vergleichs und der verschiedenen verfügbaren Hep-Snapshot-Ansichten gegeben.

3
bennidi

Nach dem Rat, einen Heap-Schnappschuss zu machen, eignen sie sich hervorragend zum Erkennen von Speicherlecks. chrome leistet hervorragende Schnappschuss-Arbeit.

In meinem Forschungsprojekt für meinen Abschluss habe ich eine interaktive Webanwendung erstellt, die eine Menge Daten in "Ebenen" generieren musste. Viele dieser Ebenen wurden in der Benutzeroberfläche "gelöscht", aber aus irgendeinem Grund war der Speicher nicht vorhanden Beim Aufheben der Zuordnung konnte ich mithilfe des Snapshot-Tools feststellen, dass JQuery eine Referenz für das Objekt gespeichert hat (die Quelle war, als ich versuchte, ein .load() -Ereignis auszulösen, bei dem die Referenz beibehalten wurde, obwohl der Gültigkeitsbereich überschritten wurde ). Wenn Sie diese Informationen im Alleingang zur Hand haben, wird mein Projekt gespeichert. Dies ist ein äußerst nützliches Tool, wenn Sie die Bibliotheken anderer Personen verwenden und nach wie vor Referenzen vorhanden sind, die verhindern, dass der GC seine Arbeit erledigt.

BEARBEITEN: Es ist auch nützlich, im Voraus zu planen, welche Aktionen ausgeführt werden sollen, um den Zeitaufwand für das Erstellen von Schnappschüssen zu minimieren, eine Hypothese zu erstellen, was das Problem verursachen könnte, und jedes Szenario zu testen und vorher und nachher Schnappschüsse zu erstellen.