Registra snapshot dell'heap

Meggin Kearney
Meggin Kearney
Sofia Emelianova
Sofia Emelianova

Scopri come registrare snapshot dell'heap con Memoria > Profili > Istantanea heap e individuare le perdite di memoria.

Il profiler heap mostra la distribuzione della memoria in base agli oggetti JavaScript della tua pagina e ai nodi DOM correlati. Utilizzalo per creare snapshot heap JS, analizzare grafici di memoria, confrontare snapshot e trovare perdite di memoria. Per ulteriori informazioni, consulta Albero di conservazione degli oggetti.

Acquisisci uno snapshot

Per creare un'istantanea dell'heap:

  1. Nella pagina che vuoi profilare, apri DevTools e vai al riquadro Memoria.
  2. Seleziona il tipo di profilazione radio_button_checked Istantanea heap, seleziona un'istanza VM JavaScript e fai clic su Crea snapshot.

Un tipo di profilazione e un'istanza VM JavaScript selezionati.

Quando il riquadro Memoria carica e analizza l'istantanea, mostra la dimensione totale degli oggetti JavaScript raggiungibili sotto il titolo dello snapshot nella sezione SNAPSHOT HEAP.

La dimensione totale degli oggetti raggiungibili.

Gli snapshot mostrano solo gli oggetti del grafico della memoria che sono raggiungibili dall'oggetto globale. L'acquisizione di uno snapshot inizia sempre con la garbage collection.

Un'istantanea dell'heap di oggetti elemento sparsi.

Cancella istantanee

Per rimuovere tutte le istantanee, fai clic su Blocca Cancella tutti i profili:

Cancella tutti i profili.

Visualizza snapshot

Per esaminare le istantanee da diverse prospettive per scopi diversi, seleziona una delle visualizzazioni dal menu a discesa in alto:

View Contenuti Finalità
Riepilogo Oggetti raggruppati per nomi dei costruttori. da usare per scovare oggetti e la loro memoria utilizzata in base al tipo. È utile per monitorare le fughe di dati nel DOM.
Confronto Differenze tra due snapshot. Utilizzala per confrontare due (o più) snapshot prima e dopo un'operazione. Conferma la presenza e la causa di una perdita di memoria esaminando il delta nella memoria libera e nel conteggio dei riferimenti.
Contenimento Contenuti heap Fornisce una visione migliore della struttura degli oggetti e consente di analizzare gli oggetti a cui viene fatto riferimento nello spazio dei nomi globale (finestra) per trovare ciò che li mantiene. Utilizzala per analizzare le chiusure e immergerti negli oggetti a basso livello.
Statistiche Grafico a torta dell'allocazione della memoria Osserva le dimensioni reali delle parti di memoria allocate a codice, stringhe, array JS, array digitati e oggetti di sistema.

La visualizzazione Riepilogo selezionata dal menu a discesa in alto.

Visualizzazione di riepilogo

Inizialmente, si apre un'istantanea dell'heap nella visualizzazione Riepilogo in cui sono elencati i costruttori in una colonna. Puoi espandere i costruttori per visualizzare gli oggetti di cui hanno creato un'istanza.

La visualizzazione Riepilogo con un costruttore espanso.

Per filtrare i costruttori non pertinenti, digita un nome che vuoi esaminare nel filtro del corso nella parte superiore della vista Riepilogo.

I numeri accanto ai nomi dei costruttori indicano il numero totale di oggetti creati con il costruttore. La visualizzazione Riepilogo mostra anche le seguenti colonne:

  • Distanza mostra la distanza alla radice utilizzando il percorso semplice più breve di nodi.
  • Dimensioni superficiali mostra la somma delle dimensioni di tutti gli oggetti creati da un determinato costruttore. La dimensione superficiale è la dimensione della memoria di un oggetto stesso. In genere, array e stringhe hanno dimensioni superficiali più grandi. Vedi anche Dimensioni degli oggetti.
  • Dimensioni conservate mostra le dimensioni massime conservate nello stesso insieme di oggetti. La dimensione conservata è la dimensione della memoria che si può liberare eliminando un oggetto e rendendo i suoi dipendenti non più raggiungibili. Vedi anche Dimensioni degli oggetti.

Quando espandi un costruttore, la visualizzazione Riepilogo mostra tutte le sue istanze. Ogni istanza riceve un'analisi delle sue dimensioni superficiali e conservate nelle colonne corrispondenti. Il numero dopo il carattere @ rappresenta l'ID univoco dell'oggetto. Consente di confrontare gli snapshot dell'heap per singolo oggetto.

Filtri costruttore

La vista Riepilogo consente di filtrare i costruttori in base ai casi comuni di utilizzo della memoria inefficiente.

Per utilizzare questi filtri, seleziona una delle seguenti opzioni dal menu a discesa all'estrema destra nella barra delle azioni:

  • Tutti gli oggetti: tutti gli oggetti acquisiti dallo snapshot corrente. Impostazione predefinita.
  • Oggetti allocati prima dello snapshot 1: oggetti creati e rimasti in memoria prima dell'acquisizione del primo snapshot.
  • Oggetti allocati tra snapshot 1 e snapshot 2: visualizza la differenza di oggetti tra lo snapshot più recente e quello precedente. Ogni nuovo snapshot aggiunge un incremento di questo filtro all'elenco a discesa.
  • Stringhe duplicate: valori di stringa che sono stati archiviati più volte in memoria.
  • Oggetti conservati da nodi scollegati: oggetti che vengono mantenuti attivi perché un nodo DOM scollegato vi fa riferimento.
  • Oggetti conservati dalla console DevTools: oggetti conservati in memoria perché sono stati valutati o con cui sono stati oggetto di interazione tramite la console DevTools.

Voci speciali nel riepilogo

Oltre a raggruppare gli oggetti per costruttori, la vista Riepilogo raggruppa anche gli oggetti per:

  • Funzioni integrate come Array o Object.
  • Funzioni definite nel codice.
  • Categorie speciali non basate su costruttori.

Voci costruttore.

(array)

Questa categoria include vari oggetti di tipo array interni che non corrispondono direttamente agli oggetti visibili in JavaScript.

Ad esempio, i contenuti degli oggetti JavaScript Array vengono archiviati in un oggetto interno secondario denominato (object elements)[], per consentire il ridimensionamento più semplice. Allo stesso modo, le proprietà con nome negli oggetti JavaScript vengono spesso archiviate in oggetti interni secondari denominati (object properties)[] elencati anche nella categoria (array).

(compiled code)

Questa categoria include i dati interni necessari a V8 per poter eseguire funzioni definite da JavaScript o WebAssembly. Ogni funzione può essere rappresentata in vari modi, da piccola e lenta a grande e veloce.

V8 gestisce automaticamente l'utilizzo della memoria in questa categoria. Se una funzione viene eseguita molte volte, V8 utilizza più memoria per quella funzione, in modo che possa essere eseguita più velocemente. Se una funzione non viene eseguita da un po' di tempo, V8 potrebbe cancellare i relativi dati interni.

(concatenated string)

Quando V8 concatena due stringhe, ad esempio con l'operatore JavaScript +, può scegliere di rappresentare il risultato internamente come una "stringa concatenata", nota anche come struttura dati Rope.

Anziché copiare tutti i caratteri delle due stringhe di origine in una nuova stringa, V8 assegna un piccolo oggetto con campi interni chiamati first e second, che puntano alle due stringhe di origine. Ciò consente a V8 di risparmiare tempo e memoria. Dal punto di vista del codice JavaScript, si tratta semplicemente di stringhe normali che si comportano come qualsiasi altra stringa.

InternalNode

Questa categoria rappresenta gli oggetti allocati al di fuori di V8, ad esempio gli oggetti C++ definiti da Blink.

Per visualizzare i nomi delle classi C++, utilizza Chrome for Testing ed esegui le seguenti operazioni:

  1. Apri DevTools e attiva le impostazioni Impostazioni > Esperimenti > check_box Mostra l'opzione per esporre i dati interni negli snapshot dell'heap.
  2. Apri il riquadro Memoria, seleziona radio_button_checked Istantanea heap e attiva radio_button_checked Esponi dati interni (include dettagli aggiuntivi specifici dell'implementazione).
  3. Riproduci il problema per cui InternalNode ha conservato molta memoria.
  4. Acquisisci un'istantanea dell'heap. In questo snapshot, gli oggetti hanno nomi delle classi C++ anziché InternalNode.
(object shape)

Come descritto in Proprietà rapide in V8, V8 tiene traccia delle classi (o forme) nascoste in modo che più oggetti con le stesse proprietà nello stesso ordine possano essere rappresentati in modo efficiente. Questa categoria contiene le classi nascoste, denominate system / Map (non correlate a JavaScript Map) e i dati correlati.

(sliced string)

Quando V8 deve prendere una sottostringa, ad esempio quando il codice JavaScript chiama String.prototype.substring(), V8 può scegliere di allocare un oggetto stringa segmentata anziché copiare tutti i caratteri pertinenti dalla stringa originale. Questo nuovo oggetto contiene un puntatore alla stringa originale e descrive quale intervallo di caratteri della stringa originale utilizzare.

Dal punto di vista del codice JavaScript, si tratta semplicemente di stringhe normali che si comportano come qualsiasi altra stringa. Se una stringa segmentata conserva molta memoria, il programma potrebbe aver attivato il problema 2869 e potrebbe essere utile adottare deliberatamente passaggi per "appiattire" la stringa segmentata.

system / Context

Gli oggetti interni di tipo system / Context contengono variabili locali di una chiusura, un ambito JavaScript a cui può accedere una funzione nidificata.

Ogni istanza di funzione contiene un puntatore interno al Context in cui viene eseguita, in modo che possa accedere a queste variabili. Anche se gli oggetti Context non sono visibili direttamente in JavaScript, hai il controllo diretto sugli oggetti.

(system)

Questa categoria contiene vari oggetti interni che non sono (ancora) stati classificati in modo più significativo.

Vista di confronto

La vista Confronto ti consente di trovare gli oggetti divulgati confrontando più snapshot tra loro. Ad esempio, eseguire un'azione e invertirla, come aprire e chiudere un documento, non dovrebbe lasciare oggetti aggiuntivi.

Per verificare che una determinata operazione non crei perdite:

  1. Acquisisci uno snapshot dell'heap prima di eseguire un'operazione.
  2. Eseguire un'operazione. In altre parole, interagisci con la pagina in un modo che ritieni possa causare una fuga di dati.
  3. Esegui un'operazione inversa. Vale a dire che devi fare l'interazione opposta e ripeterla alcune volte.
  4. Acquisisci un secondo snapshot dell'heap e modificane la visualizzazione in Confronto, confrontandolo con Snapshot 1.

La vista Confronto mostra la differenza tra due istantanee. Quando espandi una voce totale, vengono visualizzate le istanze degli oggetti aggiunti ed eliminati:

Confronto con Snapshot 1.

Vista di contenimento

La vista Contenimento è una "vista dall'alto" della struttura degli oggetti dell'applicazione. Ti consente di dare un'occhiata all'interno delle chiusure delle funzioni, osservare gli oggetti interni delle VM che insieme costituiscono gli oggetti JavaScript e comprendere quanta memoria viene utilizzata dall'applicazione a un livello molto basso.

La visualizzazione fornisce diversi punti di ingresso:

  • Oggetti DOMWindow. Oggetti globali per il codice JavaScript.
  • Radici GC. Radici GC utilizzate dal garbage collector della VM. Le root di GC possono essere costituite da mappe di oggetti integrate, tabelle di simboli, stack di thread VM, cache di compilazione, ambiti di gestione e handle globali.
  • Oggetti nativi. Oggetti del browser "inviati tramite push" all'interno della macchina virtuale JavaScript per consentire l'automazione, ad esempio nodi DOM e regole CSS.

La visualizzazione Contenimento.

Sezione Retainer

La sezione Retainer nella parte inferiore del riquadro Memoria mostra gli oggetti che puntano all'oggetto selezionato nella visualizzazione. Il riquadro Memoria aggiorna la sezione Retainer quando selezioni un oggetto diverso in una delle viste, ad eccezione di Statistiche.

La sezione Retainer.

In questo esempio, la stringa selezionata viene mantenuta dalla proprietà x di un'istanza Item.

Ignora elementi di conservazione

Puoi nascondere gli elementi di conservazione per scoprire se tra gli altri oggetti viene mantenuto quello selezionato. Con questa opzione, non è necessario rimuovere prima questo elemento di conservazione dal codice e poi acquisire nuovamente lo snapshot dell'heap.

Opzione "Ignora questo elemento di conservazione" nel menu a discesa.

Per nascondere un elemento di conservazione, fai clic con il tasto destro del mouse e seleziona Ignora questo elemento di conservazione. Gli elementi di conservazione ignorati sono contrassegnati come ignored nella colonna Distanza. Per non ignorare più tutti gli elementi di conservazione, fai clic su playlist_remove Ripristina elementi di conservazione ignorati nella barra delle azioni in alto.

Trova un oggetto specifico

Per trovare un oggetto nell'heap raccolto, puoi cercare utilizzando Ctrl + F e inserire l'ID oggetto.

Assegna un nome alle funzioni per distinguere le chiusure

È molto utile nominare le funzioni in modo da poter distinguere le chiusure nell'istantanea.

Ad esempio, il seguente codice non utilizza funzioni con nome:

function createLargeClosure() {
  var largeStr = new Array(1000000).join('x');

  var lC = function() { // this is NOT a named function
    return largeStr;
  };

  return lC;
}

Mentre in questo esempio:

function createLargeClosure() {
  var largeStr = new Array(1000000).join('x');

  var lC = function lC() { // this IS a named function
    return largeStr;
  };

  return lC;
}

Funzione con nome in una chiusura.

Individuare le fughe di notizie nel DOM

Il profiler heap è in grado di riflettere le dipendenze bidirezionali tra oggetti nativi del browser (nodi DOM e regole CSS) e oggetti JavaScript. Ciò consente di scoprire fughe di dati altrimenti invisibili a causa di sottoalberi DOM dimenticati che fluttuano in giro.

Le fughe di dati nel DOM possono essere maggiori di quanto pensi. Considera il seguente esempio. Quando viene raccolta la garbage collection di #tree?

  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 mantiene un riferimento all'elemento principale (parentNode) e in modo ricorsivo fino a #tree, quindi solo quando leafRef viene annullato l'intero albero in #tree è un candidato per la carica di Garbage Collection.

Sottoalberi del DOM