Speicherprobleme beheben

Hier erfahren Sie, wie Sie mit Chrome und den DevTools Speicherprobleme finden, die sich auf die Seitenleistung auswirken, z. B. Speicherlecks, Speicherausweitung und häufige Garbage Collection.

Zusammenfassung

  • Im Chrome-Task-Manager können Sie sehen, wie viel Arbeitsspeicher Ihre Seite belegt.
  • Mit Zeitachsenaufzeichnungen die Arbeitsspeichernutzung im Zeitverlauf visualisieren
  • Mit Heap-Snapshots können Sie getrennte DOM-Bäume (eine häufige Ursache für Speicherlecks) identifizieren.
  • Mit Aufzeichnungen der Zuweisungszeitachse können Sie herausfinden, wann im JS-Heap neuer Arbeitsspeicher zugewiesen wird.
  • Getrennte Elemente identifizieren, die durch eine JavaScript-Referenz beibehalten werden

Übersicht

Gemäß dem RAIL-Leistungsmodell sollten Sie sich bei Ihren Bemühungen um eine bessere Leistung auf Ihre Nutzer konzentrieren.

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

  • Die Leistung einer Seite verschlechtert sich im Laufe der Zeit zunehmend. Dies ist möglicherweise ein Symptom für einen Speicherleck. Ein Speicherleck tritt auf, wenn ein Fehler auf der Seite dazu führt, dass die Seite im Laufe der Zeit immer mehr Arbeitsspeicher verbraucht.
  • Die Leistung einer Seite ist durchgehend schlecht. Dies ist möglicherweise ein Symptom für eine Speicherauslastung. Eine Seite belegt zu viel Arbeitsspeicher, wenn sie mehr Arbeitsspeicher benötigt als für eine optimale Seitengeschwindigkeit erforderlich ist.
  • Die Leistung einer Seite ist verzögert oder wird häufig pausiert. Dies ist möglicherweise ein Symptom für häufige automatische Speicherbereinigungen. Bei der Garbage Collection gibt der Browser Arbeitsspeicher frei. Wann das passiert, entscheidet der Browser. Während der Datenerhebung wird die Ausführung aller Scripts pausiert. Wenn der Browser also häufig den Garbage Collector ausführt, wird die Scriptausführung häufig pausiert.

Speicherbelegung: Wie viel ist zu viel?

Ein Speicherleck lässt sich leicht definieren. Wenn eine Website immer mehr Arbeitsspeicher verbraucht, liegt ein Speicherleck vor. Die Speicherauslastung ist jedoch etwas schwieriger zu ermitteln. Was gilt als „zu viel Arbeitsspeicher“?

Hier gibt es keine genauen Zahlen, da verschiedene Geräte und Browser unterschiedliche Funktionen haben. Die gleiche Seite, die auf einem High-End-Smartphone reibungslos funktioniert, stürzt auf einem Low-End-Smartphone möglicherweise ab.

Der Schlüssel dabei ist, das RAIL-Modell zu verwenden und sich auf die Nutzer zu konzentrieren. Finden Sie heraus, welche Geräte bei Ihren Nutzern beliebt sind, und testen Sie Ihre Seite dann auf diesen Geräten. Wenn die Leistung immer wieder schlecht ist, übersteigt die Seite möglicherweise die Speicherkapazität dieser Geräte.

Arbeitsspeichernutzung mit dem Chrome-Task-Manager in Echtzeit überwachen

Verwenden Sie den Chrome-Task-Manager als Ausgangspunkt für die Untersuchung des Arbeitsspeicherproblems. Der Task-Manager ist ein Echtzeit-Monitor, der Ihnen zeigt, wie viel Arbeitsspeicher eine Seite belegt.

  1. Drücken Sie die Umschalttaste + Esc oder wählen Sie im Chrome-Hauptmenü Weitere Tools > Task-Manager aus, um den Task-Manager zu öffnen.

    Öffnen Sie den Task-Manager.

  2. Klicken Sie im Task-Manager mit der rechten Maustaste auf die Tabellenüberschrift und aktivieren Sie JavaScript-Speicher.

    JS-Speicher im Task-Manager-Header aktivieren

Diese beiden Spalten geben Aufschluss darüber, wie Ihre Seite den Arbeitsspeicher nutzt:

  • Die Spalte Speicherbedarf steht für den Betriebssystemspeicher. DOM-Knoten werden im Betriebssystemspeicher gespeichert. Wenn dieser Wert zunimmt, werden DOM-Knoten erstellt.
  • Die Spalte JavaScript-Speicher steht für den JS-Heap. Diese Spalte enthält zwei Werte. Der Wert, für den Sie sich interessieren, ist die aktuelle Anzahl (die Zahl in Klammern). Die Livezahl gibt an, wie viel Arbeitsspeicher die erreichbaren Objekte auf Ihrer Seite verbrauchen. Wenn diese Zahl steigt, werden entweder neue Objekte erstellt oder die vorhandenen Objekte werden größer.

    Task-Manager mit aktiviertem JavaScript-Speicher-Header

Speicherlecks mit Leistungsaufzeichnungen visualisieren

Sie können auch den Bereich Leistung als Ausgangspunkt für Ihre Untersuchung verwenden. Im Bereich „Leistung“ können Sie die Speichernutzung einer Seite im Zeitverlauf visualisieren.

  1. Öffnen Sie in den Entwicklertools den Bereich Leistung.
  2. Aktivieren Sie das Kästchen Arbeitsspeicher.
  3. Erstellen Sie eine Aufnahme.

Im folgenden Code wird die Aufzeichnung von Leistungs-Speicheraufzeichnungen veranschaulicht:

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 dem Dokumentkörper zehntausend div-Knoten angehängt und ein String mit einer Million x-Zeichen wird in das x-Array eingefügt. Wenn Sie diesen Code ausführen, wird eine Zeitachsenaufzeichnung wie im folgenden Screenshot erstellt:

Ein einfaches Beispiel für Wachstum.

Zuerst eine Erklärung der Benutzeroberfläche. Das Diagramm HEAP im Bereich Übersicht (unter NET) steht für den JS-Heap. Unter dem Bereich Übersicht befindet sich der Bereich Zähler. Hier sehen Sie die Arbeitsspeichernutzung aufgeschlüsselt nach JS-Heap (entspricht der Grafik HEAP im Bereich Übersicht), Dokumenten, DOM-Knoten, Listenern und GPU-Speicher. Wenn Sie ein Kästchen deaktivieren, wird es im Diagramm ausgeblendet.

Jetzt eine Analyse des Codes im Vergleich zum Screenshot. Wenn Sie sich den Knotenzähler (grüner Graph) ansehen, sehen Sie, dass er genau mit dem Code übereinstimmt. Die Anzahl der Knoten erhöht sich in diskreten Schritten. Sie können davon ausgehen, dass jede Erhöhung der Knotenanzahl einen Aufruf von grow() darstellt. Das JS-Heap-Diagramm (das blaue Diagramm) ist nicht ganz so einfach. Gemäß den Best Practices ist der erste Rückgang tatsächlich eine erzwungene Speicherbereinigung, die durch Drücken der Schaltfläche Speicher bereinigen ausgelöst wird. Im Verlauf der Aufzeichnung sehen Sie, dass die JS-Heap-Größe ansteigt. Das ist normal und zu erwarten: Der JavaScript-Code erstellt die DOM-Knoten bei jedem Tastenklick und muss viel Arbeit leisten, um den String mit einer Million Zeichen zu erstellen. Wichtig ist hier, dass der JS-Heap am Ende höher ist als am Anfang (der „Anfang“ ist hier der Punkt nach der erzwungenen Garbage Collection). In der Praxis würde dieses Muster einer zunehmenden JS-Heap- oder Knotengröße möglicherweise auf ein Speicherleck hinweisen.

Speicherlecks im getrennten DOM-Baum mit Heap-Snapshots erkennen

Ein DOM-Knoten kann nur dann automatisch bereinigt werden, wenn es weder im DOM-Baum der Seite noch im JavaScript-Code Verweise darauf gibt. Ein Knoten wird als „losgelöst“ bezeichnet, wenn er aus dem DOM-Baum entfernt wurde, aber weiterhin von JavaScript referenziert wird. Losgelöste DOM-Knoten sind eine häufige Ursache für Speicherlecks. In diesem Abschnitt erfahren Sie, wie Sie mit den Heap-Profilern von DevTools losgelöste Knoten identifizieren.

Hier 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);

Wenn Sie auf die Schaltfläche klicken, auf die im Code verwiesen wird, wird ein ul-Knoten mit zehn li-Untergeordneten erstellt. Diese Knoten werden vom Code referenziert, aber sie sind nicht im DOM-Baum vorhanden, sodass sie getrennt sind.

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

Wenn Sie einen Snapshot erstellen möchten, öffnen Sie die DevTools, gehen Sie zum Bereich Speicher, wählen Sie das Optionsfeld Heap-Snapshot aus und klicken Sie dann auf die Schaltfläche Snapshot erstellen.

Das Optionsfeld „Heap-Snapshot erstellen“ ist ausgewählt.

Die Verarbeitung und das Laden des Snapshots kann einige Zeit in Anspruch nehmen. Wählen Sie es anschließend im linken Bereich (Heap-Snapshots) aus.

Geben Sie Detached in das Eingabefeld Klassenfilter ein, um nach getrennten DOM-Baumstrukturen zu suchen.

Nach getrennten Knoten filtern

Maximieren Sie die Dreiecke, um einen getrennten Knoten zu untersuchen.

Untersuchung eines losen Baums

Klicken Sie auf einen Knoten, um ihn genauer zu untersuchen. Im Bereich Objekte finden Sie weitere Informationen zum Code, der darauf verweist. Im folgenden Screenshot sehen Sie beispielsweise, dass die Variable detachedTree auf den Knoten verweist. Um dieses bestimmte Speicherleck zu beheben, sollten Sie den Code prüfen, in dem detachedTree verwendet wird, und dafür sorgen, dass die Referenz auf den Knoten entfernt wird, wenn er nicht mehr benötigt wird.

Untersuchung eines getrennten Knotens

JS-Heap-Speicherlecks mit Zuweisungszeitachsen identifizieren

Die Zuweisungszeitachse ist ein weiteres Tool, mit dem Sie Speicherlecks in Ihrem JS-Heap aufspüren können.

Im folgenden Code wird der Zeitplan für die Zuweisung veranschaulicht:

var x = [];

function grow() {
  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, wird dem x-Array ein String mit einer Million Zeichen hinzugefügt.

Wenn Sie eine Zuweisungszeitachse aufzeichnen möchten, öffnen Sie die DevTools, gehen Sie zum Bereich Speicher, wählen Sie das Optionsfeld Zuweisungen auf Zeitachse aus, drücken Sie die Schaltfläche Aufzeichnen, führen Sie die Aktion aus, die Ihrer Meinung nach das Speicherleck verursacht, und drücken Sie dann die Schaltfläche Aufzeichnung beenden.

Achten Sie während der Aufzeichnung darauf, ob auf der Zuweisungszeitachse blaue Balken angezeigt werden, wie im folgenden Screenshot.

Neue Zuordnungen in der Leistungszeitachse.

Diese blauen Balken stehen für neue Speicherzuweisungen. Diese neuen Speicherzuweisungen sind Kandidaten für Speicherlecks. Sie können auf eine Leiste zoomen, um den Bereich Constructor so zu filtern, dass nur Objekte angezeigt werden, die im angegebenen Zeitraum zugewiesen wurden.

Eine herangezoomte Zeitachse für die Zuweisung.

Maximieren Sie das Objekt und klicken Sie auf den Wert, um weitere Details im Bereich Objekt aufzurufen. Im Screenshot unten sehen Sie beispielsweise in den Details des neu zugewiesenen Objekts, dass es der Variablen x im Bereich Window zugewiesen wurde.

Objektdetails eines String-Arrays.

Speicherzuweisung nach Funktion untersuchen

Verwenden Sie den Profiltyp Zuweisung – Stichprobenerhebung im Bereich Arbeitsspeicher, um die Arbeitsspeicherzuweisung nach JavaScript-Funktion aufzurufen.

Profiler für die Zuweisungsstichprobenerhebung im Bereich „Speicher“

  1. Wählen Sie das Optionsfeld Zuweisungsstichprobe aus. Wenn sich auf der Seite ein Worker befindet, können Sie ihn im Fenster JavaScript-VM-Instanz auswählen als Ziel für das Profiling auswählen.
  2. Drücken Sie die Schaltfläche Starten.
  3. Führen Sie die Aktionen auf der Seite aus, die Sie untersuchen möchten.
  4. Drücken Sie die Schaltfläche Stopp, wenn Sie alle Aktionen ausgeführt haben.

In den DevTools wird eine Aufschlüsselung der Arbeitsspeicherzuweisung nach Funktion angezeigt. Die Standardansicht ist Schwer (Bottom Up). Hier werden die Funktionen, denen der meiste Arbeitsspeicher zugewiesen wurde, oben angezeigt.

Ergebnisseite des Zuweisungsprofils

Objekte identifizieren, die durch eine JS-Referenz beibehalten werden

Im Profil Losgelöste Elemente werden losgelöste Elemente angezeigt, die erhalten bleiben, weil sie von JavaScript-Code referenziert werden.

Erfassen Sie ein Profil für Losgelöste Elemente, um die genauen HTML-Knoten und die Knotenanzahl zu sehen.

Beispiel für ein Profil für getrennte Elemente.

Häufige Müllabfuhren erkennen

Wenn Ihre Seite häufig pausiert, liegt möglicherweise ein Problem mit der Garbage Collection vor.

Sie können entweder den Chrome-Task-Manager oder die Speicheraufzeichnungen der Zeitachse verwenden, um häufige Garbage Collection-Vorgänge zu erkennen. Häufig ansteigende und fallende Werte für Arbeitsspeicher oder JavaScript-Speicher im Task-Manager deuten auf häufige Garbage Collection hin. In Zeitachsenaufzeichnungen weisen häufig ansteigende und abfallende Grafiken für den JS-Heap oder die Knotenanzahl auf häufige Garbage Collection hin.

Sobald Sie das Problem identifiziert haben, können Sie mithilfe einer Aufzeichnung der Zuweisungszeitachse herausfinden, wo Arbeitsspeicher zugewiesen wird und welche Funktionen die Zuweisungen verursachen.