Speicherprobleme beheben

Kayce Basques
Kayce Basques

Hier erfahren Sie, wie Sie mit Chrome und den Entwicklertools Speicherprobleme finden, die sich auf die Seitenleistung auswirken, z. B. Speicherlecks, Speicherüberlastung und häufige Garbage Collections.

Zusammenfassung

  • Mit dem Task-Manager von Chrome können Sie herausfinden, wie viel Arbeitsspeicher Ihre Seite belegt.
  • Visualisieren Sie die Speichernutzung im Zeitverlauf mit Zeitachsenaufzeichnungen.
  • Mit Heap-Snapshots können Sie getrennte DOM-Bäume identifizieren, die eine häufige Ursache für Speicherlecks sind.
  • Mit Aufzeichnungen der Zuordnungszeitachse können Sie herausfinden, wann im JS-Heap neuer Speicher zugewiesen wird.
  • Getrennte Elemente identifizieren, die durch eine JavaScript-Referenz beibehalten werden.

Übersicht

Im Sinne des RAIL-Leistungsmodells sollten Ihre Nutzer im Mittelpunkt Ihrer Leistungsbemühungen stehen.

Speicherprobleme sind wichtig, weil sie für Nutzer oft wahrnehmbar sind. Nutzer können Speicherprobleme auf folgende Weise wahrnehmen:

  • Die Leistung einer Seite verschlechtert sich im Laufe der Zeit immer mehr. Dies ist möglicherweise ein Symptom für ein Speicherleck. Ein Speicherleck liegt vor, wenn ein Fehler auf der Seite dazu führt, dass die Seite im Laufe der Zeit immer mehr Arbeitsspeicher belegt.
  • Die Leistung einer Seite ist durchgehend schlecht. Dies ist möglicherweise ein Symptom für Speicherüberlastung. Speicherüberlastung 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 automatische Speicherbereinigungen. Bei der automatischen Speicherbereinigung gibt der Browser Arbeitsspeicher frei. Der Browser entscheidet, wann dies geschieht. Während der Erfassung wird die Ausführung aller Skripts pausiert. Wenn der Browser also viel Speicherbereinigung durchführt, wird die Skriptausführung häufig pausiert.

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

Ein Speicherleck ist leicht zu definieren. Wenn eine Website immer mehr Arbeitsspeicher belegt, liegt ein Speicherleck vor. Ein aufgeblähter Arbeitsspeicher ist jedoch etwas schwieriger zu erkennen. Was gilt als „zu viel Arbeitsspeicher“?

Es gibt hier keine festen Zahlen, da verschiedene Geräte und Browser unterschiedliche Funktionen haben. Eine Seite, die auf einem High-End-Smartphone reibungslos funktioniert, kann auf einem Low-End-Smartphone abstürzen.

Der Schlüssel hierbei 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 auf diesen Geräten. Wenn die Leistung durchgängig schlecht ist, überschreitet die Seite möglicherweise die Speicherkapazität dieser Geräte.

Arbeitsspeichernutzung in Echtzeit mit dem Chrome Task-Manager überwachen

Verwenden Sie den Chrome Task Manager als Ausgangspunkt für die Untersuchung von Speicherproblemen. Der Task-Manager ist ein Echtzeitmonitor, der anzeigt, wie viel Arbeitsspeicher eine Seite belegt.

  1. Drücken Sie die Tastenkombination „Umschalttaste + Esc“ oder rufen Sie das Chrome-Hauptmenü auf und wählen Sie Weitere Tools > Taskmanager aus, um den Taskmanager zu öffnen.

    Task-Manager öffnen

  2. Rechtsklicken Sie auf die Tabellenüberschrift des Task-Managers und aktivieren Sie JavaScript-Arbeitsspeicher.

    JS-Arbeitsspeicher im Header des Task-Managers aktivieren.

Diese beiden Spalten enthalten unterschiedliche Informationen zur Speichernutzung Ihrer Seite:

  • Die Spalte Speicherbedarf stellt den Betriebssystemspeicher dar. DOM-Knoten werden im Betriebssystemspeicher gespeichert. Wenn dieser Wert steigt, werden DOM-Knoten erstellt.
  • Die Spalte JavaScript-Arbeitsspeicher stellt den JS-Heap dar. Diese Spalte enthält zwei Werte. Der Wert, der Sie interessiert, ist die Live-Nummer (die Zahl in Klammern). Die Zahl unter „Live“ 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.

    Taskmanager mit aktiviertem JavaScript-Speicherheader.

Speicherlecks mit Leistungsaufzeichnungen visualisieren

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

  1. Öffnen Sie in den Entwicklertools den Bereich Leistung.
  2. Aktivieren Sie das Kästchen Memory.
  3. Aufnahme erstellen

Um Speicheraufzeichnungen im Bereich Leistung zu demonstrieren, sehen Sie sich den folgenden Code an:

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 Dokumenttext 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) stellt den JS-Heap dar. Unter dem Bereich Übersicht befindet sich der Bereich Zähler. Hier sehen Sie die Speichernutzung aufgeschlüsselt nach JS-Heap (entspricht dem Diagramm HEAP im Bereich Übersicht), Dokumenten, DOM-Knoten, Listenern und GPU-Speicher. Wenn Sie ein Kästchen deaktivieren, wird es im Diagramm ausgeblendet.

Jetzt wird der Code mit dem Screenshot verglichen. Wenn Sie sich den Knotenzähler (die grüne Grafik) ansehen, können Sie erkennen, dass er genau mit dem Code übereinstimmt. Die Knotenanzahl erhöht sich in diskreten Schritten. Sie können davon ausgehen, dass jede Erhöhung der Knotenanzahl ein Aufruf von grow() ist. Das JS-Heap-Diagramm (das blaue Diagramm) ist nicht so einfach. Gemäß den Best Practices ist der erste Einbruch tatsächlich eine erzwungene automatische Speicherbereinigung, die durch Klicken auf die Schaltfläche Speicherbereinigung erreicht wird. Im Verlauf der Aufzeichnung ist zu sehen, dass die JS-Heap-Größe stark ansteigt. Das ist normal und zu erwarten: Der JavaScript-Code erstellt bei jedem Klick auf den Button die DOM-Knoten und muss viel Arbeit leisten, wenn er den String mit einer Million Zeichen erstellt. Der entscheidende Punkt ist, dass der JS-Heap höher endet, als er begonnen hat. Der „Anfang“ ist hier der Punkt nach der erzwungenen Speicherbereinigung. In der Praxis würde dieses Muster einer zunehmenden JS-Heap-Größe oder Knotengröße möglicherweise auf ein Speicherleck hindeuten.

Speicherlecks in getrennten DOM-Bäumen mit Heap-Snapshots erkennen

Ein DOM-Knoten kann nur dann automatisch bereinigt werden, wenn weder im DOM-Baum der Seite noch im JavaScript-Code Verweise darauf vorhanden sind. Ein Knoten wird als „getrennt“ bezeichnet, wenn er aus dem DOM-Baum entfernt wurde, aber noch von JavaScript referenziert wird. Getrennte DOM-Knoten sind eine häufige Ursache für Speicherlecks. In diesem Abschnitt erfahren Sie, wie Sie mit den Heap-Profilern der Entwicklertools getrennte 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 im Code referenzierte Schaltfläche klicken, wird ein ul-Knoten mit zehn untergeordneten li-Elementen erstellt. Diese Knoten werden vom Code referenziert, sind aber nicht im DOM-Baum vorhanden und daher losgelöst.

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 Entwicklertools und rufen Sie den Bereich Arbeitsspeicher auf. Wählen Sie das Optionsfeld Heap-Snapshot aus und klicken Sie dann auf den Button Snapshot erstellen.

Optionsfeld „Heap-Snapshot erstellen“ ausgewählt.

Es kann einige Zeit dauern, bis der Snapshot verarbeitet und geladen ist. Wenn der Vorgang abgeschlossen ist, wählen Sie den Snapshot im linken Bereich (Heap-Snapshots) aus.

Geben Sie Detached in das Eingabefeld Klassenfilter ein, um nach losgelösten DOM-Bäumen zu suchen.

Nach getrennten Knoten filtern.

Maximieren Sie die Karat, um einen losgelösten Baum zu untersuchen.

Untersuchung eines getrennten 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 Speicherleck zu beheben, müssen Sie den Code untersuchen, der detachedTree verwendet, und dafür sorgen, dass der Verweis auf den Knoten entfernt wird, wenn er nicht mehr benötigt wird.

Untersuchen eines getrennten Knotens.

JS-Heap-Speicherlecks mit Zuordnungszeitachsen identifizieren

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

Zur Veranschaulichung der Zuordnungszeitachse sehen Sie sich den folgenden Code an:

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 Array x ein String mit einer Million Zeichen hinzugefügt.

Wenn Sie eine Zuordnungszeitachse aufzeichnen möchten, öffnen Sie die Entwicklertools, rufen Sie den Bereich Arbeitsspeicher auf, wählen Sie das Optionsfeld Zuordnungen auf der Zeitachse aus, klicken Sie auf den Button Aufzeichnen, führen Sie die Aktion aus, die Ihrer Meinung nach das Speicherleck verursacht, und klicken Sie dann auf den Button Aufzeichnung beenden, wenn Sie fertig sind.

Achten Sie während der Aufzeichnung darauf, ob auf der Zeitachse für die Zuweisung blaue Balken angezeigt werden, wie im folgenden Screenshot zu sehen.

Neue Zuweisungen auf der Leistungszeitachse.

Diese blauen Balken stellen neue Arbeitsspeicherzuweisungen dar. Diese neuen Arbeitsspeicherzuweisungen sind Ihre Kandidaten für Speicherlecks. Sie können einen Balken heranzoomen, um den Bereich Konstruktor 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 seinen Wert, um im Bereich Objekt weitere Details dazu aufzurufen. Wenn Sie sich beispielsweise im Screenshot unten die Details des neu zugewiesenen Objekts ansehen, können Sie sehen, dass es der Variablen x im Bereich Window zugewiesen wurde.

Objektdetails eines String-Arrays.

Arbeitsspeicherzuweisung nach Funktion untersuchen

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

Profiler für die Stichprobenerhebung im Bereich „Arbeitsspeicher“.

  1. Wählen Sie das Optionsfeld Zuweisungsstichprobe aus. Wenn auf der Seite ein Worker vorhanden ist, können Sie ihn im Fenster JavaScript-VM-Instanz auswählen als Profilerstellungsziel auswählen.
  2. Drücke die Starttaste.
  3. Führen Sie die Aktionen auf der Seite aus, die Sie untersuchen möchten.
  4. Drücken Sie die Taste Beenden, wenn Sie alle Aktionen abgeschlossen haben.

In den DevTools wird eine Aufschlüsselung der Arbeitsspeicherzuweisung nach Funktion angezeigt. Die Standardansicht ist Heavy (Bottom Up). Hier werden die Funktionen, die den meisten Speicher zugewiesen haben, oben angezeigt.

Ergebnisseite des Zuweisungsprofils.

Durch JS-Referenz beibehaltene Objekte identifizieren

Im Profil Getrennte Elemente werden getrennte Elemente angezeigt, die beibehalten werden, weil sie von JavaScript-Code referenziert werden.

Zeichnen Sie ein Profil für Getrennte Elemente auf, um die genauen HTML-Knoten und die Knotenanzahl zu sehen.

Beispiel für ein Profil mit getrennten Elementen.

Häufige automatische Speicherbereinigungen erkennen

Wenn Ihre Seite häufig pausiert, haben Sie möglicherweise Probleme mit der automatischen Speicherbereinigung.

Sie können entweder den Chrome Task Manager oder die Zeitachsen-Speicheraufzeichnungen verwenden, um häufige Garbage Collections zu erkennen. Im Task-Manager weisen häufig steigende und fallende Werte für Arbeitsspeicher oder JavaScript-Arbeitsspeicher auf häufige automatische Speicherbereinigungen hin. In Zeitachsenaufzeichnungen weisen häufig steigende und fallende JS-Heap- oder Knotenzahl-Diagramme auf häufige automatische Speicherbereinigungen hin.

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