Registra snapshot dell'heap

Meggin Kearney
Meggin Kearney
Sofia Emelianova
Sofia Emelianova

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

Il profiler heap mostra la distribuzione della memoria in base agli oggetti JavaScript della pagina e ai nodi DOM correlati. Utilizzala per creare snapshot heap JS, analizzare i grafici della memoria, confrontare gli snapshot e trovare perdite di memoria. Per ulteriori informazioni, consulta la sezione Struttura ad albero della conservazione degli oggetti.

Acquisisci uno snapshot

Per acquisire un'istantanea heap:

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

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

Quando il riquadro Memoria carica e analizza lo snapshot, mostra le dimensioni totali degli oggetti JavaScript raggiungibili sotto il titolo dello snapshot nella sezione SNAPSHOTS HEAP.

La dimensione totale degli oggetti raggiungibili.

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

Un'istantanea heap di oggetti elemento sparsi.

Cancella snapshot

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:

Visualizza Contenuti Finalità
Riepilogo Oggetti raggruppati per nomi costruttori. Utilizzala per individuare gli oggetti e il loro utilizzo della memoria 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 ispezionando il delta nella memoria liberata e nel conteggio dei riferimenti.
Contenimento Contenuti heap Fornisce una visione migliore della struttura degli oggetti e aiuta ad analizzare gli oggetti a cui viene fatto riferimento nello spazio dei nomi globale (finestra) per trovare cosa li mantiene. Usala per analizzare le chiusure e analizzare gli oggetti a un livello basso.
Statistiche Grafico a torta dell'allocazione della memoria Visualizza le dimensioni reali delle parti di memoria allocate a codice, stringhe, array JS, array digitati e oggetti di sistema.

La visualizzazione Riepilogo selezionata nel menu a discesa in alto.

Visualizzazione di riepilogo

Inizialmente, nella visualizzazione Riepilogo si apre un'istantanea dell'heap in cui una colonna riporta i Costruttori. Puoi espandere i costruttori per visualizzare gli oggetti per 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 corso nella parte superiore della visualizzazione Riepilogo.

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

  • Distanza mostra la distanza dalla radice utilizzando il percorso semplice più breve dei nodi.
  • Dimensioni superficiali mostra la somma delle dimensioni superficiali di tutti gli oggetti creati da un determinato costruttore. Per dimensioni superficiali si intende la dimensione della memoria trattenuta da un oggetto stesso. In genere, array e stringhe hanno dimensioni superficiali più grandi. Vedi anche Dimensioni degli oggetti.
  • Dimensioni conservate mostra la dimensione massima conservata nello stesso insieme di oggetti. Le dimensioni conservate rappresentano la dimensione della memoria che puoi liberare eliminando un oggetto e rendendo i suoi elementi dipendenti non più raggiungibili. Vedi anche Dimensioni degli oggetti.

Quando espandi un costruttore, la visualizzazione Riepilogo mostra tutte le sue istanze. Ogni istanza riceve una suddivisione delle dimensioni superficiali e conservate nelle colonne corrispondenti. Il numero dopo il carattere @ è l'ID univoco dell'oggetto. Ti consente di confrontare le istantanee heap in base al singolo oggetto.

Voci speciali in Riepilogo

Oltre a raggruppare gli oggetti in base ai costruttori, la visualizzazione Riepilogo raggruppa gli oggetti anche in base a:

  • Funzioni integrate come Array o Object.
  • Funzioni definite nel codice.
  • Categorie speciali che non si basano sui costruttori.

Voci del costruttore.

(array)

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

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

(compiled code)

Questa categoria include dati interni necessari a V8 per poter eseguire funzioni definite da JavaScript o WebAssembly. Ogni funzione può essere rappresentata in vari modi, da piccolo e lento 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 dati interni per quella funzione.

(concatenated string)

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

Anziché copiare tutti i caratteri delle due stringhe di origine in una nuova stringa, V8 alloca 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, queste sono solo stringhe normali e si comportano come qualsiasi altra stringa.

InternalNode

Questa categoria rappresenta gli oggetti assegnati al di fuori di V8, come 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 gli elementi interni negli snapshot heap.
  2. Apri il riquadro Memoria, seleziona radio_button_checked Istantanea heap, quindi attiva radio_button_checked Esponi interni (include ulteriori dettagli specifici dell'implementazione).
  3. Riproduci il problema che ha causato la conservazione di molta memoria in InternalNode.
  4. Acquisisci un'istantanea heap. In questo snapshot, gli oggetti hanno nomi di classi C++ anziché InternalNode.
(object shape)

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

(sliced string)

Quando V8 deve utilizzare una sottostringa, ad esempio quando il codice JavaScript chiama String.prototype.substring(), V8 potrebbe scegliere di allocare un oggetto stringa tagliata 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, queste sono solo stringhe normali e si comportano come qualsiasi altra stringa. Se una stringa segmentata conserva molta memoria, il programma potrebbe aver attivato il problema 2869 e potrebbe trarre vantaggio dall'adozione di passaggi deliberati 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 da JavaScript, puoi controllarli direttamente.

(system)

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

Vista di confronto

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

Per verificare che una determinata operazione non crei perdite:

  1. Acquisisci un'istantanea heap prima di eseguire un'operazione.
  2. Esegui un'operazione. In altre parole, interagisci con una pagina in un modo che ritieni possa causare una fuga di notizie.
  3. Esegui un'operazione inversa. In altre parole, esegui l'interazione opposta e ripetila alcune volte.
  4. Acquisisci una seconda istantanea heap e modificane la visualizzazione in Confronto, confrontandola con Istantanea 1.

La visualizzazione Confronto mostra la differenza tra due snapshot. Quando si espande una voce totale, vengono visualizzate le istanze dell'oggetto aggiunte ed eliminate:

Confronto con l'istantanea 1.

Vista di contenimento

La vista Contenimento è una "vista dall'alto" della struttura degli oggetti dell'applicazione. Consente di dare un'occhiata alle chiusure delle funzioni, di osservare gli oggetti interni delle VM che insieme costituiscono i tuoi oggetti JavaScript e di comprendere la quantità di memoria 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. I certificati radice GC possono essere costituiti da mappe di oggetti integrate, tabelle di simboli, stack di thread di VM, cache di compilazione, ambiti di gestione e handle globali.
  • Oggetti nativi. Oggetti browser "push" all'interno della macchina virtuale JavaScript per consentire l'automazione, ad esempio nodi DOM e regole CSS.

La vista di contenimento.

La sezione assistente in sito

La sezione Conservatori nella parte inferiore del riquadro Memoria mostra gli oggetti che puntano all'oggetto selezionato nella visualizzazione.

La sezione assistente in sito.

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

Trovare un oggetto specifico

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

Funzioni dei nomi per distinguere le chiusure

È molto utile assegnare un nome alle funzioni in modo da distinguere le chiusure nello snapshot.

Ad esempio, il codice seguente 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;
}

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.

Scoprire fughe di dati nel DOM

Il profiler heap ha la capacità di riflettere le dipendenze bidirezionali tra gli oggetti nativi del browser (nodi DOM e regole CSS) e gli oggetti JavaScript. Ciò consente di scoprire fughe di notizie altrimenti invisibili che si verificano a causa di sottoalberi DOM dimenticati che fluttuano intorno.

Le perdite nel DOM possono essere più grandi di quanto pensi. Considera l'esempio che segue. Quando viene raccolta la spazzatura 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 padre (parentNode) e in modo ricorsivo fino a #tree, quindi solo quando leafRef viene annullato, l'intero albero sotto #tree diventa un candidato per GC.

Sottoalberi DOM