Scopri come registrare istantanee heap con Memoria > Profili > Istantanea heap e trovare perdite di memoria.
Il profiler dell'heap mostra la distribuzione della memoria in base agli oggetti JavaScript della tua pagina e ai nodi DOM correlati. Utilizzalo per acquisire istantanee dell'heap JS, analizzare i grafici della memoria, confrontare le istantanee e trovare perdite di memoria. Per ulteriori informazioni, consulta Albero di conservazione degli oggetti.
Scatta una foto
Per acquisire un'istantanea dell'heap:
- In una pagina di cui vuoi creare il profilo, apri DevTools e vai al riquadro Memoria.
- Seleziona il tipo di profilazione Snapshot dell'heap , poi seleziona un'istanza VM JavaScript e fai clic su Acquisisci snapshot.
Quando il riquadro Memoria carica e analizza l'istantanea, mostra le dimensioni totali degli oggetti JavaScript raggiungibili sotto il titolo dell'istantanea nella sezione ISTANTEANEE HEAP.
Gli snapshot mostrano solo gli oggetti del grafico della memoria che sono raggiungibili dall'oggetto globale. L'acquisizione di un'istantanea inizia sempre con la raccolta dei rifiuti.
.Cancellare gli snapshot
Per rimuovere tutte le istantanee, fai clic su
Cancella tutti i profili:Visualizza snapshot
Per esaminare gli istantanei da prospettive diverse e per scopi diversi, seleziona una delle visualizzazioni dal menu a discesa in alto:
Visualizza | Contenuti | Finalità |
---|---|---|
Riepilogo | Oggetti raggruppati per nomi dei costruttori. | Utilizzalo per individuare gli oggetti e il loro utilizzo della memoria in base al tipo. Utile per monitorare le fughe di dati DOM. |
Confronto | Differenze tra due istantanee. | Utilizzalo per confrontare due o più istantanee, prima e dopo un'operazione. Verifica la presenza e la causa di una perdita di memoria controllando il delta nella memoria liberata e nel conteggio dei riferimenti. |
Contenimento | Contenuti dell'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 (window) per trovare ciò che li mantiene attivi. Utilizzalo per analizzare le chiusure e approfondire gli oggetti a basso livello. |
Statistiche | Grafico a torta dell'allocazione della memoria | Visualizza le dimensioni relative delle parti di memoria allocate a codice, stringhe, array JS, array con tipi e oggetti di sistema. |
Visualizzazione riepilogo
Inizialmente, nella visualizzazione Riepilogo si apre uno snapshot dell'heap che elenca i Costruttori in una colonna. Puoi espandere i costruttori per visualizzare gli oggetti che hanno creato.
Per filtrare i costruttori irrilevanti, digita un nome da ispezionare in Filtro classi 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 dalla radice utilizzando il percorso semplice più breve dei nodi.
- Dimensioni poco profonde mostra la somma delle dimensioni poco profonde di tutti gli oggetti creati da un determinato costruttore. Le dimensioni ridotte corrispondono alle dimensioni della memoria occupata dall'oggetto stesso. In genere, gli array e le stringhe hanno dimensioni più grandi. Vedi anche Dimensioni degli oggetti.
- Dimensioni conservate mostra le dimensioni massime conservate nello stesso insieme di oggetti. La dimensione trattenuta indica la quantità di memoria che puoi liberare eliminando un oggetto e rendendo non più raggiungibili i relativi elementi dipendenti. Vedi anche Dimensioni degli oggetti.
Quando espandi un costruttore, la visualizzazione Riepilogo mostra tutte le sue istanze. Ogni istanza riceve una suddivisione delle dimensioni ridotte e conservate nelle colonne corrispondenti. Il numero dopo il carattere @
è l'ID univoco dell'oggetto. Ti consente di confrontare gli snapshot dell'heap in base a ciascun oggetto.
Filtri del costruttore
La visualizzazione Riepilogo ti consente di filtrare i costruttori in base a casi comuni di utilizzo inefficiente della memoria.
Per utilizzare questi filtri, seleziona una delle seguenti opzioni dal menu a discesa più a destra nella barra delle azioni:
- Tutti gli oggetti: tutti gli oggetti acquisiti dallo snapshot corrente. Impostato per impostazione predefinita.
- Oggetti allocati prima dello snapshot 1: gli oggetti creati e rimasti in memoria prima del primo snapshot.
- Oggetti allocati tra gli istantanei 1 e 2: visualizza la differenza di oggetti tra l'istantanea più recente e quella precedente. Ogni nuovo istantanea aggiunge un incremento di questo filtro all'elenco a discesa.
- Stringhe duplicate: valori di stringa memorizzati più volte in memoria.
- Oggetti conservati dai nodi scollegati: oggetti che vengono mantenuti attivi perché un nodo DOM scollegato fa riferimento a loro.
- Oggetti conservati dalla console DevTools: oggetti memorizzati in memoria perché sono stati valutati o con cui è stata eseguita un'interazione tramite la console DevTools.
Voci speciali in Riepilogo
Oltre a raggruppare gli oggetti per costruttore, la visualizzazione Riepilogo raggruppa gli oggetti anche in base a:
- Funzioni integrate come
Array
oObject
. - Elementi HTML raggruppati per tag, ad esempio
<div>
,<a>
,<img>
e altri. - Funzioni che hai definito nel codice.
- Categorie speciali che non si basano sui costruttori.
(array)
Questa categoria include vari oggetti interni simili ad array che non corrispondono direttamente agli oggetti visibili in JavaScript.
Ad esempio, i contenuti degli oggetti Array
di JavaScript vengono archiviati in un oggetto interno secondario denominato (object elements)[]
per consentire un ridimensionamento più semplice. Analogamente, le proprietà denominate negli oggetti JavaScript vengono spesso archiviate in oggetti interni secondari denominati (object properties)[]
, che sono elencati anche nella categoria (array)
.
(compiled code)
Questa categoria include i dati interni di cui V8 ha bisogno per eseguire funzioni definite da JavaScript o WebAssembly. Ogni funzione può essere rappresentata in vari modi, da piccole e lente a grandi e veloci.
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 relativi a quella funzione.
(concatenated string)
Quando V8 concatena due stringhe, ad esempio con l'operatore +
di JavaScript, può scegliere di rappresentare il risultato internamente 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 rimandano alle due stringhe di origine. In questo modo, V8 risparmia tempo e memoria. Dal punto di vista del codice JavaScript, si tratta di normali stringhe 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 per i test e svolgi i seguenti passaggi:
- Apri DevTools e attiva Impostazioni > Esperimenti > Mostra opzione per esporre gli elementi interni negli snapshot dell'heap.
- Apri il riquadro Memoria, seleziona Istantanea dell'heap e attiva Esponi dati interni (include dettagli aggiuntivi specifici per l'implementazione).
- Riproduci il problema che ha causato il mantenimento di molta memoria da parte di
InternalNode
. - Acquisisci un'istantanea dell'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 delle 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 Map
di JavaScript) 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 tagliata anziché copiare tutti i caratteri pertinenti dalla stringa originale. Questo nuovo oggetto contiene un puntatore alla stringa originale e descrive l'intervallo di caratteri della stringa originale da utilizzare.
Dal punto di vista del codice JavaScript, si tratta di normali stringhe che si comportano come qualsiasi altra stringa. Se una stringa suddivisa occupa molta memoria, il programma potrebbe aver attivato il problema 2869 e potrebbe trarre vantaggio dall'adozione di misure deliberate per "appiattire" la stringa suddivisa.
system / Context
Gli oggetti interni di tipo system / Context
contengono variabili locali di una chiusura, ovvero 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 da poter accedere a queste variabili. Anche se gli oggetti Context
non sono direttamente visibili da JavaScript, hai il controllo diretto su di essi.
(system)
Questa categoria contiene vari oggetti interni che non sono (ancora) stati classificati in modo più significativo.
Vista di confronto
La visualizzazione Confronto ti consente di trovare gli oggetti trapelati confrontando più istantanee tra loro. Ad esempio, l'esecuzione di un'azione e la sua inversione, come l'apertura e la chiusura di un documento, non deve lasciare oggetti aggiuntivi.
Per verificare che una determinata operazione non crei perdite:
- Crea uno snapshot dell'heap prima di eseguire un'operazione.
- Esegui un'operazione. In altre parole, interagisci con una pagina in un modo che ritieni possa causare una fuga di dati.
- Esegui un'operazione inversa. In altre parole, esegui l'interazione opposta e ripetila alcune volte.
- Acquisisci un secondo snapshot dell'heap e imposta la visualizzazione su Confronto, confrontandolo con Snapshot 1.
La visualizzazione Confronto mostra la differenza tra due istantanee. Quando espandi una voce di totale, vengono mostrate le istanze di oggetti aggiunte ed eliminate:
Visualizzazione Contenimento
La visualizzazione Contenimento è una "panoramica" della struttura degli oggetti dell'applicazione. Ti consente di dare un'occhiata all'interno delle chiusure di funzione, di osservare gli oggetti interni della VM che insieme costituiscono gli oggetti JavaScript e di capire quanta memoria viene utilizzata dalla tua applicazione a un livello molto basso.
La visualizzazione offre diversi punti di contatto:
- Oggetti DOMWindow. Oggetti globali per il codice JavaScript.
- Radici GC. Radici GC utilizzate dal garbage collector della VM. Le radici del GC possono essere costituite da mappe di oggetti integrate, tabelle di simboli, stack di thread VM, cache di compilazione, ambiti di handle e handle globali.
- Oggetti nativi. Oggetti del browser "inviati" all'interno della macchina virtuale JavaScript per consentire l'automazione, ad esempio i nodi DOM e le regole CSS.
La sezione Apparecchi di contenzione
La sezione Contenitori nella parte inferiore del riquadro Memoria mostra gli oggetti che rimandano all'oggetto selezionato nella visualizzazione. Il riquadro Memoria aggiorna la sezione Prenotazioni quando selezioni un altro oggetto in una delle visualizzazioni, ad eccezione di Statistiche.
In questo esempio, la stringa selezionata viene conservata dalla proprietà x
di un'istanza Item
.
Ignorare gli elementi di conservazione
Puoi nascondere i fermi per scoprire se altri oggetti mantengono quello selezionato. Con questa opzione, non è necessario rimuovere prima questo fermo dal codice e poi acquisire di nuovo lo snapshot dell'heap.
Per nascondere un fermo, fai clic con il tasto destro del mouse e seleziona Ignora questo fermo. I retainer ignorati sono contrassegnati come ignored
nella colonna Distanza. Per smettere di ignorare tutti i retainer, fai clic su Ripristina retainer ignorati nella barra delle azioni in alto.
Trovare un oggetto specifico
Per trovare un oggetto nell'heap raccolto, puoi eseguire una ricerca utilizzando Ctrl + F e inserire l'ID oggetto.
Assegnare un nome alle funzioni per distinguere le chiusure
È molto utile assegnare un nome alle funzioni per distinguere le chiusure nello snapshot.
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 questo esempio:
function createLargeClosure() {
var largeStr = new Array(1000000).join('x');
var lC = function lC() { // this IS a named function
return largeStr;
};
return lC;
}
Scoprire perdite DOM
Il profiler dell'heap è in grado di riflettere le dipendenze bidirezionali tra gli oggetti nativi del browser (nodi DOM e regole CSS) e gli oggetti JavaScript. In questo modo è possibile scoprire perdite altrimenti invisibili dovute a sottoalberi DOM scollegati dimenticati.
Le fughe di dati DOM possono essere più gravi di quanto pensi. Considera l'esempio seguente. Quando viene raccolta la spazzatura #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 al relativo elemento principale (parentNode
) e in modo ricorsivo fino a #tree
, pertanto solo quando leafRef
viene annullato l'intero albero sotto #tree
è un candidato per la GC.