Speicherprobleme beheben

Lernen Sie, wie Sie Chrome und die DevTools verwenden, um Speicherprobleme zu finden, die sich auf die Seitenleistung auswirken, einschließlich Speicherlecks, Speicheraufblähung und häufige Garbage Collections.

Zusammenfassung #

  • Finden Sie mit dem Chrome Task Manager heraus, wie viel Speicher Ihre Seite derzeit verwendet.
  • Visualisieren Sie die Speichernutzung im Zeitverlauf mit Timeline-Aufzeichnungen.
  • Identifizieren Sie abgetrennte DOM-Bäume (eine häufige Ursache für Speicherlecks) mit Heap-Snapshots.
  • Finden Sie heraus, wann neuer Speicher in Ihrem JS-Heap mit Allocation Timeline-Aufnahmen zugewiesen wird.

Übersicht

Im Sinne des RAIL-Performance-Modells sollten Ihre Benutzer im Mittelpunkt Ihrer Performance-Bemühungen stehen.

Speicherprobleme sind wichtig, weil sie oft von Benutzern wahrgenommen werden. Benutzer können Speicherprobleme auf folgende Weise wahrnehmen:

  • Die Leistung einer Seite wird mit der Zeit immer schlechter. Dies ist möglicherweise ein Symptom für ein Speicherleck. Ein Speicherleck liegt vor, wenn ein Fehler in der Seite dazu führt, dass die Seite im Laufe der Zeit immer mehr Speicher verbraucht.
  • Die Leistung einer Seite ist konstant schlecht. Dies ist möglicherweise ein Symptom für Speicheraufblähung. Speicheraufblähung liegt vor, wenn eine Seite mehr Speicher verwendet, als für eine optimale Seitengeschwindigkeit erforderlich ist.
  • Die Leistung einer Seite ist verzögert oder scheint häufig zu pausieren. Dies ist möglicherweise ein Symptom für häufige Garbage Collections. Garbage Collection ist, wenn der Browser Speicher zurückfordert. Der Browser entscheidet, wann dies geschieht. Während der Sammlungen wird die gesamte Skriptausführung angehalten. Wenn der Browser also häufig Garbage Collections durchführt, wird die Skriptausführung häufig unterbrochen.

Speicheraufblähung: Wie viel ist „zu viel“?

Ein Speicherleck ist einfach zu definieren. Wenn eine Website nach und nach immer mehr Speicher verbraucht, dann haben Sie ein Leck. Aber Speicheraufblähung ist ein bisschen schwieriger zu definieren. Was gilt als „zu viel Speicherverbrauch“?

Hier gibt es keine harten Zahlen, da verschiedene Geräte und Browser unterschiedliche Fähigkeiten haben. Die gleiche Seite, die auf einem High-End-Smartphone reibungslos läuft, kann auf einem Low-End-Smartphone abstürzen.

Der Schlüssel hier ist, das RAIL-Modell zu verwenden und sich auf Ihre Benutzer zu konzentrieren. Finden Sie heraus, welche Geräte bei Ihren Nutzern beliebt sind, und testen Sie dann Ihre Seite auf diesen Geräten. Wenn die Erfahrung durchweg schlecht ist, kann die Seite die Speicherkapazitäten dieser Geräte überschreiten.

Überwachen Sie die Speichernutzung in Echtzeit mit dem Chrome Task Manager

Nutzen Sie den Chrome Task Manager als Ausgangspunkt für Ihre Untersuchung des Speicherproblems. Der Task-Manager ist ein Echtzeit-Monitor, der Ihnen mitteilt, wie viel Speicher eine Seite gerade verbraucht.

  1. Drücken Sie Umschalt+Esc oder gehen Sie ins Chrome-Hauptmenü und wählen Sie Mehr Tools > Task-Manager, um den Task-Manager zu öffnen.

    Öffnen des Task-Managers

  2. Klicken Sie mit der rechten Maustaste auf den Tabellenkopf des Task-Managers und aktivieren Sie den JavaScript-Speicher.

    JS-Speicher aktivieren

Diese beiden Spalten sagen Ihnen unterschiedliche Dinge darüber, wie Ihre Seite den Speicher nutzt:

  • Die Spalte Speicher stellt den nativen Speicher dar. DOM-Knoten werden im Nativspeicher gespeichert. Wenn dieser Wert ansteigt, werden DOM-Knoten erstellt.
  • Die Spalte JavaScript-Speicher stellt den JS-Heap dar. Diese Spalte enthält zwei Werte. Der Wert, an dem Sie interessiert sind, ist die Live-Zahl (die Zahl in Klammern). Die Live-Zahl stellt dar, wie viel Speicher die erreichbaren Objekte auf Ihrer Seite verwenden. Wenn diese Zahl steigt, werden entweder neue Objekte erstellt oder die vorhandenen Objekte wachsen.

Speicherlecks mit Timeline-Aufnahmen visualisieren

Sie können auch das Timeline-Panel als weiteren Ausgangspunkt für Ihre Untersuchung verwenden. Das Zeitleistenfenster hilft Ihnen, die Speichernutzung einer Seite im Laufe der Zeit zu visualisieren.

  1. Öffnen Sie das Zeitleistenfenster in DevTools.
  2. Aktivieren Sie das Kontrollkästchen Speicher.
  3. Erstellen Sie eine Aufnahme.

Tipp: Es ist eine gute Praxis, Ihre Aufnahme mit einer erzwungenen Garbage Collection zu beginnen und zu beenden. Klicken Sie während der Aufnahme auf die Schaltfläche „Collect Garbage“ (Schaltfläche ), um die Garbage Collection zu erzwingen.

Zur Veranschaulichung von Timeline-Speicheraufnahmen betrachten Sie den folgenden Code:

var x = ;
function grow() {
for (var i = 0; i < 10000; i++) {
document.body.appendChild(document.createElement('div'));
}
x.push(new Array(1000000).join('x'));
}
document.getElementById('grow').addEventListener('click', grow);

Jedes Mal, wenn die im Code referenzierte Schaltfläche gedrückt wird, werden zehntausend div-Knoten an den Dokumentkörper angehängt und eine Zeichenkette mit einer Million x-Zeichen in das x-Array geschoben. Die Ausführung dieses Codes erzeugt eine Timeline-Aufnahme wie im folgenden Screenshot:

Einfaches Wachstumsbeispiel

Zunächst eine Erklärung der Benutzeroberfläche. Der HEAP-Graph im Übersichtsfenster (unter NET) stellt den JS-Heap dar. Unterhalb des Übersichtsfensters befindet sich das Zähler-Fenster. Hier sehen Sie die Speichernutzung aufgeschlüsselt nach JS-Heap (wie im HEAP-Diagramm im Übersichtsfenster), Dokumenten, DOM-Knoten, Listenern und GPU-Speicher. Wenn Sie ein Kontrollkästchen deaktivieren, wird es aus dem Diagramm ausgeblendet.

Nun noch eine Analyse des Codes im Vergleich zum Screenshot. Wenn Sie sich den Knotenzähler (den grünen Graphen) ansehen, können Sie sehen, dass er sauber mit dem Code übereinstimmt. Die Knotenanzahl steigt in diskreten Schritten an. Sie können davon ausgehen, dass jeder Anstieg der Knotenanzahl ein Aufruf von grow() ist. Der JS-Heap-Graph (der blaue Graph) ist nicht so einfach. In Übereinstimmung mit Best Practices ist der erste Einbruch tatsächlich eine erzwungene Garbage Collection (erreicht durch Drücken der Schaltfläche collect garbage). Im weiteren Verlauf der Aufzeichnung können Sie sehen, dass die JS-Heap-Größe in die Höhe schießt. Das ist natürlich und zu erwarten: Der JavaScript-Code erstellt die DOM-Knoten bei jedem Schaltflächenklick und macht eine Menge Arbeit, wenn er die Zeichenkette mit einer Million Zeichen erstellt. Das Entscheidende hier ist die Tatsache, dass der JS-Heap höher endet als er begonnen hat (der „Anfang“ ist hier der Punkt nach der erzwungenen Garbage Collection). Wenn Sie in der realen Welt dieses Muster der zunehmenden JS-Heap-Größe oder Knotengröße sehen, würde dies möglicherweise ein Speicherleck bedeuten.

Discover detached DOM tree memory leaks with Heap Snapshots #

Ein DOM-Knoten kann nur dann Garbage Collection unterzogen werden, wenn es keine Referenzen auf ihn gibt, weder vom DOM-Baum der Seite noch vom JavaScript-Code. Ein Knoten wird als „losgelöst“ bezeichnet, wenn er aus dem DOM-Baum entfernt wurde, aber ein Teil des JavaScript-Codes noch auf ihn verweist. Abgetrennte DOM-Knoten sind eine häufige Ursache für Speicherlecks. In diesem Abschnitt lernen Sie, wie Sie die Heap-Profiler von DevTools verwenden können, um losgelöste Knoten zu identifizieren.

Hier ist ein einfaches Beispiel für losgelöste DOM-Knoten.

var detachedTree;
function create() {
var ul = document.createElement('ul');
for (var i = 0; i < 10; i++) {
var li = document.createElement('li');
ul.appendChild(li);
}
detachedTree = ul;
}
document.getElementById('create').addEventListener('click', create);

Der Klick auf die im Code referenzierte Schaltfläche erzeugt einen ul-Knoten mit zehn li-Kindern. Diese Knoten werden vom Code referenziert, existieren aber nicht im DOM-Baum, sind also losgelöst.

Heap-Snapshots sind eine Möglichkeit, losgelöste Knoten zu identifizieren. Wie der Name schon sagt, zeigen Heap-Snapshots, wie der Speicher unter den JS-Objekten und DOM-Knoten Ihrer Seite zum Zeitpunkt des Snapshots verteilt ist.

Um einen Snapshot zu erstellen, öffnen Sie DevTools und gehen Sie zum Bedienfeld „Profile“, wählen Sie das Optionsfeld „Heap-Snapshot aufnehmen“ und drücken Sie dann die Schaltfläche „Snapshot aufnehmen“.

Heap-Snapshot aufnehmen

Der Snapshot kann einige Zeit zum Verarbeiten und Laden benötigen. Sobald er fertig ist, wählen Sie ihn im linken Bedienfeld aus (namens HEAP SNAPSHOTS).

Geben Sie Detached in das Textfeld Klassenfilter ein, um nach abgetrennten DOM-Bäumen zu suchen.

Filtern nach abgetrennten Knoten

Erweitern Sie die Karat, um einen abgetrennten Baum zu untersuchen.

Untersuchung eines abgetrennten Baums

Gelb hervorgehobene Knoten haben direkte Referenzen auf sie aus dem JavaScript-Code. Rot hervorgehobene Knoten haben keine direkten Verweise. Sie sind nur lebendig, weil sie Teil des Baums des gelben Knotens sind. Im Allgemeinen möchten Sie sich auf die gelben Knoten konzentrieren. Korrigieren Sie Ihren Code so, dass der gelbe Knoten nicht länger als nötig lebendig ist, und beseitigen Sie auch die roten Knoten, die Teil des Baums des gelben Knotens sind.

Klicken Sie auf einen gelben Knoten, um ihn näher zu untersuchen. Im Objektbereich können Sie weitere Informationen über den Code sehen, der ihn referenziert. Im Screenshot unten sehen Sie zum Beispiel, dass die Variable detachedTree auf den Knoten verweist. Um dieses spezielle Speicherleck zu beheben, würden Sie den Code untersuchen, der detachedTree verwendet, und sicherstellen, dass er seine Referenz auf den Knoten entfernt, wenn er nicht mehr benötigt wird.

Untersuchung eines gelben Knotens

Identifizieren von JS-Heap-Speicherlecks mit Allocation Timelines

Die Allocation Timeline ist ein weiteres Werkzeug, das Ihnen helfen kann, Speicherlecks in Ihrem JS-Heap aufzuspüren.

Um die Allocation Timeline zu demonstrieren, betrachten Sie den folgenden Code:

var x = ;
function grow() {
x.push(new Array(1000000).join('x'));
}
document.getElementById('grow').addEventListener('click', grow);

Jedes Mal, wenn die Schaltfläche, auf die im Code verwiesen wird, gedrückt wird, wird eine Zeichenkette mit einer Million Zeichen zum x-Array hinzugefügt.

Um eine Zuweisungs-Zeitleiste aufzuzeichnen, öffnen Sie DevTools, gehen Sie zum Bedienfeld „Profile“, wählen Sie die Optionsschaltfläche „Zuweisungs-Zeitleiste aufzeichnen“, drücken Sie die Schaltfläche „Start“, führen Sie die Aktion aus, von der Sie vermuten, dass sie das Speicherleck verursacht, und drücken Sie dann die Schaltfläche „Aufnahme stoppen“ (Schaltfläche ), wenn Sie fertig sind.

Beobachten Sie während der Aufnahme, ob blaue Balken auf der Zuweisungs-Zeitleiste erscheinen, wie im folgenden Screenshot.

Neue Zuweisungen

Diese blauen Balken repräsentieren neue Speicherzuweisungen. Diese neuen Speicherallokationen sind Ihre Kandidaten für Speicherlecks. Sie können auf einen Balken zoomen, um das Konstruktorfenster zu filtern und nur Objekte anzuzeigen, die in dem angegebenen Zeitraum alloziert wurden.

Zoomed allocation timeline

Erweitern Sie das Objekt und klicken Sie auf seinen Wert, um weitere Details darüber im Objektfenster anzuzeigen. Wenn Sie sich zum Beispiel im folgenden Screenshot die Details des neu zugewiesenen Objekts ansehen, sehen Sie, dass es der x Variablen im Window Bereich zugewiesen wurde.

Objektdetails

Speicherzuweisung nach Funktion untersuchen

Verwenden Sie den Typ Record Allocation Profiler, um die Speicherzuweisung nach JavaScript-Funktion zu betrachten.

Record Allocation Profiler

  1. Wählen Sie das Optionsfeld Record Allocation Profiler. Wenn es auf der Seite einen Worker gibt, können Sie diesen als Profiling-Ziel auswählen, indem Sie das Dropdown-Menü neben der Schaltfläche Start verwenden.
  2. Drücken Sie die Schaltfläche Start.
  3. Führen Sie die Aktionen auf der Seite aus, die Sie untersuchen möchten.
  4. Drücken Sie die Schaltfläche Stop, wenn Sie alle Ihre Aktionen abgeschlossen haben.

DevTools zeigt Ihnen eine Aufschlüsselung der Speicherzuweisung nach Funktion. Die Standardansicht ist Heavy (Bottom Up), die die Funktionen, die den meisten Speicher zugewiesen haben, oben anzeigt.

Zuweisungsprofil

Häufige Garbage Collections aufspüren

Wenn Ihre Seite häufig zu pausieren scheint, haben Sie möglicherweise Probleme mit der Garbage Collection.

Sie können entweder den Chrome Task-Manager oder die Timeline-Speicheraufzeichnungen verwenden, um häufige Garbage Collections zu erkennen. Im Task-Manager stellen häufig steigende und fallende Speicher- oder JavaScript-Speicherwerte häufige Garbage Collections dar. In Timeline-Aufnahmen weisen häufig steigende und fallende JS-Heap- oder Node-Count-Diagramme auf häufige Garbage Collections hin.

Wenn Sie das Problem identifiziert haben, können Sie eine Allocation Timeline-Aufnahme verwenden, um herauszufinden, wo Speicher zugewiesen wird und welche Funktionen die Zuweisungen verursachen.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.