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 Chrome-Taskmanager können Sie herausfinden, wie viel Arbeitsspeicher Ihre Seite verwendet.
- Mit Zeitachsenaufzeichnungen können Sie 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 neuer Speicher in Ihrem JS-Heap zugewiesen wird.
- Getrennte Elemente identifizieren, die durch eine JavaScript-Referenz beibehalten werden.
Übersicht
Gemäß dem RAIL-Leistungsmodell sollten Sie sich bei Ihren Leistungsbemühungen auf Ihre Nutzer konzentrieren.
Speicherprobleme sind wichtig, weil sie von Nutzern oft bemerkt werden. Nutzer können Speicherprobleme auf folgende Weise wahrnehmen:
- Die Leistung einer Seite verschlechtert sich im Laufe der Zeit immer weiter. 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 verwendet.
- Die Leistung einer Seite ist dauerhaft schlecht. Dies ist möglicherweise ein Symptom für Memory Bloat. Von Memory Bloat spricht man, wenn eine Seite mehr Arbeitsspeicher verwendet als für eine optimale Seitengeschwindigkeit erforderlich ist.
- Die Leistung einer Seite wird 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 das passiert. Während der Erfassung wird die gesamte Skriptausführung pausiert. Wenn der Browser also viele Garbage-Collection-Vorgänge durchführt, wird die Skriptausführung häufig pausiert.
Speicher-Bloat: Wie viel ist „zu viel“?
Ein Speicherleck lässt sich leicht definieren. Wenn eine Website immer mehr Arbeitsspeicher verwendet, liegt ein Speicherleck vor. Speicher-Bloat ist jedoch etwas schwieriger zu identifizieren. Was bedeutet „zu viel Arbeitsspeicher verwenden“?
Hier gibt es keine festen Zahlen, da verschiedene Geräte und Browser unterschiedliche Funktionen haben. Dieselbe Seite, die auf einem High-End-Smartphone reibungslos funktioniert, kann auf einem Low-End-Smartphone abstürzen.
Wichtig ist hier, das RAIL-Modell zu verwenden und sich auf Ihre 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 Nutzererfahrung durchweg schlecht ist, überschreitet die Seite möglicherweise die Speicherkapazitäten 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 Arbeitsspeicherproblemen. Der Task-Manager ist ein Echtzeitmonitor, der Ihnen anzeigt, wie viel Arbeitsspeicher eine Seite verwendet.
Drücken Sie die Umschalttaste + Esc oder rufen Sie das Chrome-Hauptmenü auf und wählen Sie Weitere Tools > Task-Manager aus, um den Task-Manager zu öffnen.
Klicken Sie mit der rechten Maustaste auf die Tabellenüberschrift des Task-Managers und aktivieren Sie JavaScript-Arbeitsspeicher.
Diese beiden Spalten geben Aufschluss darüber, wie Ihre Seite Arbeitsspeicher nutzt:
- Die Spalte Speicherbedarf steht für den Betriebssystemspeicher. DOM-Knoten werden im Arbeitsspeicher des Betriebssystems gespeichert. Wenn dieser Wert zunimmt, werden DOM-Knoten erstellt.
Die Spalte JavaScript Memory (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 Live-Zahl gibt an, wie viel Arbeitsspeicher die erreichbaren Objekte auf Ihrer Seite verwenden. Wenn diese Zahl steigt, werden entweder neue Objekte erstellt oder die vorhandenen Objekte werden größer.
Speicherlecks mit Leistungsaufzeichnungen visualisieren
Sie können auch das Leistungsfeld als Ausgangspunkt für Ihre Untersuchung verwenden. Im Bereich „Leistung“ können Sie die Speichernutzung einer Seite im Zeitverlauf visualisieren.
- Öffnen Sie in den Entwicklertools den Bereich Leistung.
- Aktivieren Sie das Kästchen Informationen merken.
- Aufnahme erstellen
Betrachten wir den folgenden Code, um Performance-Speicheraufzeichnungen zu veranschaulichen:
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:
Zuerst wird die Benutzeroberfläche erläutert. Das HEAP-Diagramm im Bereich Übersicht (unter NET) stellt den JS-Heap dar. Unter dem Bereich Übersicht befindet sich der Bereich Zähler. Hier sehen Sie die Arbeitsspeichernutzung aufgeschlüsselt nach JS-Heap (entspricht dem HEAP-Diagramm im Bereich Übersicht), Dokumenten, DOM-Knoten, Listenern und GPU-Arbeitsspeicher. Wenn Sie ein Kästchen deaktivieren, wird der entsprechende Messwert im Diagramm ausgeblendet.
Nun folgt eine Analyse des Codes im Vergleich zum Screenshot. Wenn Sie sich den Knoten-Zähler (das grüne Diagramm) ansehen, sehen Sie, dass er genau mit dem Code übereinstimmt. Die Anzahl der Knoten erhöht sich in diskreten Schritten. Jede Erhöhung der Knotenzahl ist ein Aufruf von grow()
. Der JS-Heap-Graph (die blaue Linie) ist nicht so einfach zu interpretieren. Entsprechend den Best Practices ist der erste Einbruch tatsächlich eine erzwungene automatische Speicherbereinigung (durch Drücken der Schaltfläche Collect Garbage (Speicher bereinigen) erreicht). Während 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 Klicken auf die Schaltfläche und führt viel Arbeit aus, wenn er den String mit einer Million Zeichen erstellt. Wichtig ist hier, dass der JS-Heap höher endet als er begonnen hat (der „Beginn“ ist hier der Punkt nach der erzwungenen Garbage Collection). In der Praxis würde dieses Muster einer zunehmenden JS-Heap-Größe oder Knotengröße möglicherweise auf ein Speicherleck hindeuten.
Arbeitsspeicherlecks in getrennten DOM-Bäumen mit Heap-Snapshots erkennen
Ein DOM-Knoten kann nur automatisch bereinigt werden, wenn es keine Verweise darauf aus dem DOM-Baum der Seite oder aus JavaScript-Code gibt. Ein Knoten wird als „abgetrennt“ bezeichnet, wenn er aus dem DOM-Baum entfernt wurde, aber in JavaScript noch darauf verwiesen wird. Getrennte DOM-Knoten sind eine häufige Ursache für Speicherlecks. In diesem Abschnitt erfahren Sie, wie Sie mit den Heap-Profilern von DevTools getrennte Knoten identifizieren.
Hier ein einfaches Beispiel für getrennte 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 li
-Unterknoten erstellt. Auf diese Knoten wird im Code verwiesen, sie sind aber nicht im DOM-Baum vorhanden und daher getrennt.
Heap-Snapshots sind eine Möglichkeit, getrennte Knoten zu identifizieren. Wie der Name schon sagt, zeigen Heap-Snapshots, wie der Arbeitsspeicher zu einem bestimmten Zeitpunkt auf die JS-Objekte und DOM-Knoten Ihrer Seite verteilt ist.
Wenn Sie einen Snapshot erstellen möchten, öffnen Sie die DevTools, rufen Sie das Memory-Panel auf, wählen Sie das Optionsfeld Heap Snapshot aus und klicken Sie dann auf die Schaltfläche Take snapshot.
Die Verarbeitung und das Laden des Snapshots kann einige Zeit dauern. Wenn der Vorgang abgeschlossen ist, wählen Sie den Snapshot im linken Bereich aus (Heap-Snapshots).
Geben Sie Detached
in das Eingabefeld Klassenfilter ein, um nach getrennten DOM-Bäumen zu suchen.
Maximieren Sie die Winkel, um einen separaten Baum zu untersuchen.
Klicken Sie auf einen Knoten, um ihn genauer zu untersuchen. Im Bereich Objects (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, müssen Sie den Code untersuchen, in dem detachedTree
verwendet wird, und dafür sorgen, dass die Referenz zum Knoten entfernt wird, wenn sie nicht mehr benötigt wird.
JS-Heap-Speicherlecks mit Zuweisungszeitachsen erkennen
Die Zuweisungszeitachse ist ein weiteres Tool, mit dem Sie Speicherlecks in Ihrem JS-Heap aufspüren können.
Zur Veranschaulichung der Zuweisungszeitachse betrachten wir den folgenden Code:
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, rufen Sie den Bereich Arbeitsspeicher auf, wählen Sie das Optionsfeld Zuweisungen auf der Zeitachse aus, klicken Sie auf die Schaltfläche
Aufzeichnen, führen Sie die Aktion aus, die Ihrer Meinung nach das Speicherleck verursacht, und klicken Sie dann auf die Schaltfläche Aufzeichnung beenden.Achten Sie während der Aufzeichnung darauf, ob in der Zuweisungszeitachse blaue Balken angezeigt werden, wie im folgenden Screenshot.
Die blauen Balken stehen für neue Speicherzuweisungen. Diese neuen Speicherzuweisungen sind Ihre Kandidaten für Speicherlecks. Sie können eine Leiste vergrößern, um den Bereich Constructor so zu filtern, dass nur Objekte angezeigt werden, die im angegebenen Zeitraum zugewiesen wurden.
Maximieren Sie das Objekt und klicken Sie auf seinen Wert, um weitere Details dazu im Bereich Objekt aufzurufen. Im Screenshot unten sehen Sie beispielsweise, dass das neu zugewiesene Objekt der Variablen x
im Bereich Window
zugewiesen wurde.
Arbeitsspeicherzuweisung nach Funktion untersuchen
Verwenden Sie im Bereich Arbeitsspeicher den Profiltyp Zuweisungs-Sampling, um die Arbeitsspeicherzuweisung nach JavaScript-Funktion aufzurufen.
- Wählen Sie das Optionsfeld Zuteilungs-Sampling aus. Wenn auf der Seite ein Worker vorhanden ist, können Sie ihn im Fenster JavaScript-VM-Instanz auswählen als Profiling-Ziel auswählen.
- Drücken Sie die Starttaste.
- Führen Sie die Aktionen auf der Seite aus, die Sie untersuchen möchten.
- Drücken Sie die Schaltfläche Stopp, wenn Sie alle Aktionen abgeschlossen haben.
In den DevTools wird eine Aufschlüsselung der Speicherzuweisung nach Funktion angezeigt. Die Standardansicht ist Schwer (Bottom-up). Hier werden die Funktionen, denen der meiste Speicher zugewiesen wurde, oben angezeigt.
Objekte identifizieren, die durch eine JS‑Referenz beibehalten werden
Im Profil Getrennte Elemente sehen Sie getrennte Elemente, die beibehalten werden, weil sie von JavaScript-Code referenziert werden.
Erstellen Sie ein Profil vom Typ Abgetrennte Elemente, um die genauen HTML-Knoten und die Anzahl der Knoten zu sehen.
Häufige automatische Speicherbereinigungen 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 Collections zu erkennen. Im Task-Manager stellen häufig steigende und fallende Arbeitsspeicher- oder JavaScript-Arbeitsspeicher-Werte häufige automatische Speicherbereinigungen dar. In Zeitachsendiagrammen weisen häufig steigende und fallende Diagramme für JS-Heap oder Knotenzahl auf häufige Garbage Collections hin.
Sobald Sie das Problem identifiziert haben, können Sie mit einer Aufzeichnung der Zuweisungszeitachse herausfinden, wo Speicher zugewiesen wird und welche Funktionen die Zuweisungen verursachen.