Weitere Informationen zum Erfassen von Heap-Snapshots mit Arbeitsspeicher > Profile > Heap-Snapshot und zum Auffinden von Speicherlecks
Der Heap-Profiler zeigt die Arbeitsspeicherverteilung für die JavaScript-Objekte und die zugehörigen DOM-Knoten Ihrer Seite an. Sie können damit JS-Heap-Snapshots erstellen, Speicherdiagramme analysieren, Snapshots vergleichen und Speicherlecks finden. Weitere Informationen finden Sie unter Objektbeibehaltungsstruktur.
Schnappschuss aufnehmen
So erstellen Sie einen Heap-Snapshot:
- Öffnen Sie die Entwicklertools auf einer Seite, für die Sie ein Profil erstellen möchten, und gehen Sie zum Bereich Memory.
- Wählen Sie den Profilerstellungstyp Heap-Snapshot aus, wählen Sie eine JavaScript-VM-Instanz aus und klicken Sie auf Snapshot erstellen.
Wenn das Steuerfeld Arbeitsspeicher den Snapshot lädt und parst, wird die Gesamtgröße der erreichbaren JavaScript-Objekte unter dem Snapshot-Titel im Bereich HEAP-SNAPSHOTS angezeigt.
Snapshots zeigen nur die Objekte aus dem Speicherdiagramm an, die über das globale Objekt erreichbar sind. Das Erstellen eines Snapshots beginnt immer mit der Garbage Collection.
Snapshots löschen
Wenn Sie alle Snapshots entfernen möchten, klicken Sie auf
Alle Profile löschen:Snapshots anzeigen
Wenn Sie Snapshots aus verschiedenen Perspektiven und zu verschiedenen Zwecken prüfen möchten, wählen Sie oben im Drop-down-Menü eine der Ansichten aus:
Ansehen | Inhalt | Zweck |
---|---|---|
Zusammenfassung | Objekte, die nach Konstruktornamen gruppiert sind. | Mit dieser Funktion können Sie nach Objekten und ihrer Speichernutzung nach Typ suchen. Hilfreich zum Nachverfolgen von DOM-Lecks. |
Vergleich | Unterschiede zwischen zwei Snapshots. | Damit können Sie zwei oder mehr Snapshots vor und nach einer Operation vergleichen. Prüfen Sie das Vorhandensein und die Ursache eines Speicherlecks, indem Sie die Differenz zwischen freigegebenem Arbeitsspeicher und Referenzzählung prüfen. |
Begrenzung | Heap-Inhalte | Bietet eine bessere Übersicht über die Objektstruktur und hilft bei der Analyse von Objekten, auf die im globalen Namespace (Fenster) verwiesen wird, um herauszufinden, was sie am Leben hält. Damit können Sie Schleifen analysieren und Ihre Objekte auf niedriger Ebene untersuchen. |
Statistiken | Kreisdiagramm zur Arbeitsspeicherzuweisung | Sehen Sie sich die tatsächlichen Größen von Speicherteilen an, die Code, Strings, JS-Arrays, typisierten Arrays und Systemobjekten zugewiesen sind. |
Zusammenfassung
Zuerst wird in der Ansicht Zusammenfassung ein Heap-Snapshot geöffnet, in dem die Konstruktoren in einer Spalte aufgeführt sind. Sie können Konstruktoren erweitern, um die von ihnen instanziierten Objekte zu sehen.
Wenn Sie irrelevante Konstruktoren herausfiltern möchten, geben Sie oben in der Ansicht Zusammenfassung in den Klassenfilter einen Namen ein, den Sie prüfen möchten.
Die Zahlen neben den Konstruktornamen geben die Gesamtzahl der mit dem Konstruktor erstellten Objekte an. In der Ansicht Zusammenfassung sind außerdem die folgenden Spalten zu sehen:
- Entfernung zeigt die Entfernung zum Stamm mithilfe des kürzesten einfachen Knotenpfads an.
- Größe ohne Unterobjekte ist die Summe der Größen ohne Unterobjekte aller Objekte, die mit einem bestimmten Konstruktor erstellt wurden. Die Shallow-Größe ist die Größe des Arbeitsspeichers, der von einem Objekt selbst belegt wird. Arrays und Strings haben in der Regel eine größere flache Größe. Siehe auch Objektgrößen.
- Beibehaltene Größe zeigt die maximale beibehaltene Größe innerhalb desselben Satzes von Objekten. Beibehaltene Größe ist die Größe des Arbeitsspeichers, den Sie freigeben können, indem Sie ein Objekt löschen und seine abhängigen Elemente nicht mehr erreichbar machen. Siehe auch Objektgrößen.
Wenn Sie einen Konstruktor maximieren, werden in der Ansicht Zusammenfassung alle seine Instanzen angezeigt. Für jede Instanz wird in den entsprechenden Spalten eine Aufschlüsselung der flachen und beibehaltenen Größen angezeigt. Die Zahl nach dem Zeichen @
ist die eindeutige ID des Objekts. Damit können Sie Heap-Snapshots objektweise vergleichen.
Konstruktorfilter
In der Ansicht Zusammenfassung können Sie Konstruktoren anhand von häufigen Fällen ineffizienter Speichernutzung filtern.
Wenn Sie diese Filter verwenden möchten, wählen Sie in der Aktionsleiste im rechten Drop-down-Menü eine der folgenden Optionen aus:
- Alle Objekte: alle Objekte, die im aktuellen Snapshot erfasst wurden. Standardmäßig festgelegt.
- Objekte, die vor Snapshot 1 zugewiesen wurden: Objekte, die erstellt wurden und im Arbeitsspeicher verblieben, bevor der erste Snapshot aufgenommen wurde.
- Zwischen Snapshot 1 und Snapshot 2 zugewiesene Objekte: Hier sehen Sie den Unterschied zwischen den Objekten im jeweils letzten und im vorherigen Snapshot. Mit jedem neuen Snapshot wird der Drop-down-Liste ein weiterer Wert dieses Filters hinzugefügt.
- Doppelte Strings: Stringwerte, die mehrmals im Arbeitsspeicher gespeichert wurden.
- Von getrennten Knoten aufbewahrte Objekte: Objekte, die beibehalten werden, weil ein getrennter DOM-Knoten auf sie verweist.
- Von der Entwicklertools-Konsole aufbewahrte Objekte: Objekte, die im Arbeitsspeicher gehalten werden, weil sie über die Entwicklertools-Konsole ausgewertet oder mit ihnen interagiert wurden.
Sondereinträge in der Zusammenfassung
In der Ansicht Zusammenfassung werden Objekte nicht nur nach Konstruktoren, sondern auch nach folgenden Kriterien gruppiert:
- Integrierte Funktionen wie
Array
oderObject
- HTML-Elemente, die nach ihren Tags gruppiert sind, z. B.
<div>
,<a>
oder<img>
. - Funktionen, die Sie in Ihrem Code definiert haben.
- Spezielle Kategorien, die nicht auf Konstruktoren basieren.
(array)
Diese Kategorie umfasst verschiedene interne arrayähnliche Objekte, die nicht direkt den in JavaScript sichtbaren Objekten entsprechen.
So wird beispielsweise der Inhalt von JavaScript-Array
-Objekten in einem sekundären internen Objekt namens (object elements)[]
gespeichert, um die Größe leichter ändern zu können. Ebenso werden die benannten Attribute in JavaScript-Objekten häufig in sekundären internen Objekten namens (object properties)[]
gespeichert, die ebenfalls in der Kategorie (array)
aufgeführt sind.
(compiled code)
Diese Kategorie enthält interne Daten, die V8 benötigt, um von JavaScript oder WebAssembly definierte Funktionen auszuführen. Jede Funktion kann auf unterschiedliche Weise dargestellt werden, von klein und langsam bis groß und schnell.
V8 verwaltet die Speichernutzung in dieser Kategorie automatisch. Wenn eine Funktion viele Male ausgeführt wird, benötigt V8 mehr Arbeitsspeicher für diese Funktion, damit sie schneller ausgeführt werden kann. Wenn eine Funktion längere Zeit nicht ausgeführt wurde, löscht V8 möglicherweise die internen Daten für diese Funktion.
(concatenated string)
Wenn V8 zwei Strings zusammenführt, z. B. mit dem JavaScript-Operator +
, kann das Ergebnis intern als „zusammengesetzter String“ dargestellt werden, auch bekannt als Rope-Datenstruktur.
Anstatt alle Zeichen der beiden Quellstrings in einen neuen String zu kopieren, weist V8 ein kleines Objekt mit den internen Feldern first
und second
zu, die auf die beiden Quellstrings verweisen. So spart V8 Zeit und Arbeitsspeicher. Aus Sicht von JavaScript-Code sind dies ganz normale Strings, die sich wie jeder andere String verhalten.
InternalNode
Diese Kategorie umfasst Objekte, die außerhalb von V8 zugewiesen werden, z. B. C++-Objekte, die von Blink definiert werden.
Wenn Sie C++-Klassennamen sehen möchten, verwenden Sie Chrome for Testing und führen Sie die folgenden Schritte aus:
- Öffnen Sie die DevTools und aktivieren Sie Einstellungen > Experimente > Option zum Anzeigen von internen Informationen in Heap-Snapshots anzeigen.
- Öffnen Sie den Bereich Speicher, wählen Sie Heap-Snapshot aus und aktivieren Sie das Kästchen Interne Informationen offenlegen (enthalten zusätzliche implementierungsspezifische Details).
- Reproduzieren Sie das Problem, das dazu geführt hat, dass die
InternalNode
viel Arbeitsspeicher belegt. - Erstellen Sie einen Heap-Snapshot. In diesem Snapshot haben Objekte C++ Klassennamen anstelle von
InternalNode
.
(object shape)
Wie unter Schnelle Eigenschaften in V8 beschrieben, überwacht V8 ausgeblendete Klassen (oder Formen), damit mehrere Objekte mit denselben Eigenschaften in derselben Reihenfolge effizient dargestellt werden können. Diese Kategorie enthält diese versteckten Klassen, die system / Map
(nicht zu verwechseln mit JavaScript Map
) heißen, und zugehörige Daten.
(sliced string)
Wenn V8 einen Teilstring benötigt, z. B. wenn JavaScript-Code String.prototype.substring()
aufruft, kann V8 ein Objekt vom Typ „gespaltener String“ zuweisen, anstatt alle relevanten Zeichen aus dem ursprünglichen String zu kopieren. Dieses neue Objekt enthält einen Verweis auf den ursprünglichen String und beschreibt, welcher Bereich von Zeichen aus dem ursprünglichen String verwendet werden soll.
Aus Sicht von JavaScript-Code sind dies ganz normale Strings, die sich wie jeder andere String verhalten. Wenn ein gesplitterter String viel Arbeitsspeicher belegt, hat das Programm möglicherweise Problem 2869 ausgelöst. In diesem Fall kann es sinnvoll sein, den gesplitterten String zu „flechten“.
system / Context
Interne Objekte vom Typ system / Context
enthalten lokale Variablen aus einem Closure, einem JavaScript-Bereich, auf den eine verschachtelte Funktion zugreifen kann.
Jede Funktionsinstanz enthält einen internen Verweis auf den Context
, in dem sie ausgeführt wird, damit sie auf diese Variablen zugreifen kann. Auch wenn Context
-Objekte in JavaScript nicht direkt sichtbar sind, haben Sie die direkte Kontrolle darüber.
(system)
Diese Kategorie enthält verschiedene interne Objekte, die (noch) nicht sinnvoller kategorisiert wurden.
Vergleichsansicht
In der Ansicht Vergleich können Sie durch den Vergleich mehrerer Snapshots gehackte Objekte finden. Wenn Sie beispielsweise eine Aktion ausführen und rückgängig machen, z. B. ein Dokument öffnen und schließen, sollten keine zusätzlichen Objekte zurückbleiben.
So prüfen Sie, ob ein bestimmter Vorgang keine Lecks verursacht:
- Erstellen Sie einen Heap-Snapshot, bevor Sie einen Vorgang ausführen.
- Führen Sie einen Vorgang aus. Interagieren Sie also auf eine Weise mit einer Seite, die Ihrer Meinung nach zu einem Datenleck führen könnte.
- Führen Sie einen umgekehrten Vorgang aus. Führen Sie also die gegensätzliche Interaktion durch und wiederholen Sie dies einige Male.
- Erstellen Sie einen zweiten Heap-Snapshot und ändern Sie die Ansicht in Vergleich. Vergleichen Sie ihn mit Snapshot 1.
In der Ansicht Vergleich sehen Sie den Unterschied zwischen zwei Snapshots. Wenn Sie einen Gesamteintrag maximieren, werden hinzugefügte und gelöschte Objektinstanzen angezeigt:
Ansicht „Eindämmung“
Die Ansicht Begrenzung bietet eine Vogelperspektive der Objektstruktur Ihrer Anwendung. Sie können sich Funktionsschließungen ansehen, interne VM-Objekte beobachten, die zusammen Ihre JavaScript-Objekte bilden, und auf sehr niedriger Ebene nachvollziehen, wie viel Arbeitsspeicher Ihre Anwendung benötigt.
Die Ansicht bietet mehrere Einstiegspunkte:
- DOMWindow-Objekte. Globale Objekte für JavaScript-Code.
- GC-Roots GC-Roots, die vom automatischen Speicherbereinigung der VM verwendet werden. GC-Wurzeln können aus integrierten Objektkarten, Symboltabellen, VM-Thread-Stacks, Kompilierungscaches, Handle-Bereichen und globalen Handles bestehen.
- Native Objekte Browserobjekte, die in die JavaScript-virtuelle Maschine „geschoben“ werden, um Automatisierung zu ermöglichen, z. B. DOM-Knoten und CSS-Regeln.
Bereich „Retainer“
Im Bereich Retainers (Behaltene Objekte) unten im Bereich Memory (Speicher) werden Objekte angezeigt, die auf das in der Ansicht ausgewählte Objekt verweisen. Im Bereich Speicher wird der Bereich Besitzer aktualisiert, wenn Sie in einer der Ansichten (außer Statistiken) andere Objekte auswählen.
In diesem Beispiel wird der ausgewählte String durch die x
-Eigenschaft einer Item
-Instanz beibehalten.
Retainer ignorieren
Sie können Halterungen ausblenden, um herauszufinden, ob andere Objekte die ausgewählten beibehalten. Mit dieser Option müssen Sie diesen Retainer nicht zuerst aus dem Code entfernen und dann den Heap-Snapshot noch einmal aufnehmen.
Wenn Sie einen Retainer ausblenden möchten, klicken Sie mit der rechten Maustaste darauf und wählen Sie Diesen Retainer ignorieren aus. Ignorierte Retainer sind in der Spalte Entfernung als ignored
gekennzeichnet. Wenn du alle Abos wieder aktivieren möchtest, klicke oben in der Aktionsleiste auf Ignored retainers restore (Ignorierte Abos wiederherstellen).
Bestimmtes Objekt finden
Wenn Sie ein Objekt im erfassten Heap finden möchten, können Sie mit Strg + F nach der Objekt-ID suchen.
Funktionen benennen, um Schleifen zu unterscheiden
Es ist sehr hilfreich, die Funktionen zu benennen, damit Sie im Snapshot zwischen den Schließungen unterscheiden können.
Im folgenden Code werden beispielsweise keine benannten Funktionen verwendet:
function createLargeClosure() {
var largeStr = new Array(1000000).join('x');
var lC = function() { // this is NOT a named function
return largeStr;
};
return lC;
}
In diesem Beispiel ist das nicht der Fall:
function createLargeClosure() {
var largeStr = new Array(1000000).join('x');
var lC = function lC() { // this IS a named function
return largeStr;
};
return lC;
}
DOM-Lecks aufdecken
Der Heap-Profiler kann bidirektionale Abhängigkeiten zwischen browsereigenen Objekten (DOM-Knoten und CSS-Regeln) und JavaScript-Objekten widerspiegeln. So lassen sich sonst unsichtbare Lecks aufdecken, die durch vergessene, losgelöste DOM-Unterbäume verursacht werden.
DOM-Leaks können größer sein, als Sie denken. Dazu ein Beispiel: Wann wird der #tree
-Speicher automatisch bereinigt?
var select = document.querySelector;
var treeRef = select("#tree");
var leafRef = select("#leaf");
var body = select("body");
body.removeChild(treeRef);
//#tree can't be GC yet due to treeRef
treeRef = null;
//#tree can't be GC yet due to indirect
//reference from leafRef
leafRef = null;
//#NOW #tree can be garbage collected
#leaf
enthält einen Verweis auf sein übergeordnetes Element (parentNode
) und rekursiv bis zu #tree
. Nur wenn leafRef
auf Null gesetzt wird, ist der gesamte Baum unter #tree
ein Kandidat für die GC.