Risolvere i problemi di memoria

Scopri come utilizzare Chrome e DevTools per individuare i problemi di memoria che influiscono sulle prestazioni delle pagine, tra cui perdite di memoria, sovraccarichi di memoria e frequenti garbage collection.

Riepilogo

  • Scopri quanta memoria è attualmente in uso nella tua pagina grazie al Task Manager di Chrome.
  • Visualizza l'utilizzo della memoria nel tempo con le registrazioni degli Spostamenti.
  • Identifica alberi DOM scollegati (una causa comune di fughe di memoria) con gli snapshot heap.
  • Scopri quando viene allocata nuova memoria nell'heap di JS con le registrazioni degli Spostamenti di allocazione.

Panoramica

Nello spirito del modello di prestazioni RAIL, le attività legate alle prestazioni devono concentrarsi sugli utenti.

I problemi di memoria sono importanti perché spesso sono percepiti dagli utenti. Gli utenti possono percepire i problemi di memoria nei seguenti modi:

  • Il rendimento di una pagina peggiora progressivamente. Questo potrebbe essere il sintomo di una perdita di memoria. Una perdita di memoria si verifica quando un bug nella pagina fa sì che la pagina utilizzi progressivamente sempre più memoria nel tempo.
  • Il rendimento di una pagina è costantemente scadente. Potrebbe trattarsi di un sintomo di gonfiore della memoria. Si verifica un gonfiore di memoria quando una pagina utilizza più memoria di quella necessaria per una velocità ottimale della pagina.
  • Le prestazioni di una pagina vengono ritardate o sembrano essere messe in pausa frequentemente. Questo è probabilmente un sintomo di frequenti garbage collection. La garbage collection si verifica quando il browser recupera memoria. È il browser che decide quando succede. Durante le raccolte, l'esecuzione dello script è messa in pausa. Quindi se il browser fa garbage collection molto, l'esecuzione dello script verrà messa in pausa molto.

Eccesso di memoria: quanto è "troppo"?

Una perdita di memoria è facile da definire. Se un sito utilizza progressivamente sempre più memoria, significa che si è verificata una fuga di dati. Ma la memoria gonfia è un po' più difficile da fissare. Cosa si intende per "utilizzo eccessivo di memoria"?

Non ci sono numeri reali qui, perché dispositivi e browser diversi hanno funzionalità diverse. La stessa pagina che funziona perfettamente su uno smartphone di fascia alta potrebbe arrestarsi in modo anomalo su uno smartphone di fascia bassa.

In questo caso, il segreto è usare il modello RAIL e concentrarsi sugli utenti. Scopri quali sono i dispositivi più diffusi tra i tuoi utenti, quindi testa la tua pagina su questi dispositivi. Se l'esperienza è costantemente negativa, la pagina potrebbe superare le capacità di memoria di questi dispositivi.

Monitora l'utilizzo della memoria in tempo reale con Chrome Task Manager

Utilizza Task Manager di Chrome come punto di partenza per l'indagine sui problemi di memoria. Task Manager è un monitoraggio in tempo reale che indica la quantità di memoria attualmente utilizzata da una pagina.

  1. Premi Maiusc + Esc o vai al menu principale di Chrome e seleziona Altri strumenti > Task Manager per aprire Task Manager.

    Apertura di Task Manager

  2. Fai clic con il tasto destro del mouse sull'intestazione della tabella di Task Manager e attiva Memoria JavaScript.

    Attivazione della memoria JS in corso...

Queste due colonne indicano informazioni diverse sull'utilizzo della memoria da parte della pagina:

  • La colonna Memoria rappresenta la memoria nativa. I nodi DOM sono archiviati nella memoria nativa. Se questo valore aumenta, vengono creati i nodi DOM.
  • La colonna Memoria JavaScript rappresenta l'heap di JS. Questa colonna contiene due valori. Il valore che ti interessa è il numero in tempo reale (il numero tra parentesi). Il numero attivo rappresenta la quantità di memoria utilizzata dagli oggetti raggiungibili sulla tua pagina. Se questo numero aumenta, è in corso la creazione di nuovi oggetti oppure quelli esistenti sono in crescita.

Visualizza le fughe di memoria con le registrazioni delle prestazioni

Puoi anche utilizzare il riquadro Rendimento come punto di partenza per l'indagine. Il riquadro Prestazioni ti consente di visualizzare l'utilizzo della memoria di una pagina nel tempo.

  1. Apri il riquadro Rendimento in DevTools.
  2. Attiva la casella di controllo Memoria.
  3. Effettua una registrazione.

Per dimostrare le registrazioni della memoria delle prestazioni, considera il codice seguente:

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);

Ogni volta che viene premuto il pulsante a cui viene fatto riferimento nel codice, vengono aggiunti diecimila nodi div al corpo del documento e viene inviata una stringa di un milione di caratteri x all'array x. L'esecuzione di questo codice produce una registrazione della sequenza temporale come il seguente screenshot:

esempio di crescita semplice

Innanzitutto, una spiegazione dell'interfaccia utente. Il grafico HEAP nel riquadro Panoramica (sotto NET) rappresenta l'heap di JS. Sotto il riquadro Panoramica è presente il riquadro Contatore. Qui puoi vedere l'utilizzo della memoria suddiviso per heap JS (come per il grafico HEAP nel riquadro Panoramica), documenti, nodi DOM, listener e memoria GPU. Se viene disattivata, una casella di controllo la nasconde nel grafico.

Ora, un'analisi del codice confrontata con lo screenshot. Se osservi il contatore dei nodi (il grafico verde), puoi vedere che corrisponde perfettamente al codice. Il numero di nodi aumenta in passaggi discreti. Puoi presumere che ogni aumento del conteggio dei nodi sia una chiamata a grow(). Il grafico heap di JS (il grafico blu) non è così semplice. In linea con le best practice, il primo dip è in realtà una garbage collection forzata (ottenuta premendo il pulsante collect garbage). Man mano che la registrazione avanza, puoi notare che le dimensioni dell'heap di JS aumentano. Si tratta di un comportamento normale e previsto: il codice JavaScript crea i nodi DOM a ogni clic di un pulsante e svolge molto lavoro alla creazione di una stringa composta da un milione di caratteri. L'aspetto fondamentale in questo caso è il fatto che l'heap JS termina più in alto di quanto abbia iniziato (il "inizio" qui è il punto dopo la garbage collection forzata). Nel mondo reale, se noti questo pattern di aumento della dimensione dell'heap di JS o della dimensione del nodo, potrebbe potenzialmente significare una perdita di memoria.

Scopri le perdite di memoria ad albero DOM scollegate con gli snapshot dell'heap

Un nodo DOM può essere garbage collection solo quando non esistono riferimenti alla struttura DOM o al codice JavaScript della pagina. Un nodo viene detto "scollegato" quando viene rimosso dall'albero DOM, ma alcuni JavaScript vi fanno comunque riferimento. I nodi DOM scollegati sono una causa comune di perdite di memoria. Questa sezione insegna come utilizzare i profiler heap di DevTools per identificare i nodi scollegati.

Ecco un semplice esempio di nodi DOM scollegati.

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);

Facendo clic sul pulsante a cui si fa riferimento nel codice viene creato un nodo ul con dieci li figlio. A questi nodi il codice fa riferimento, ma non esistono nell'albero DOM, quindi vengono scollegati.

Gli snapshot dell'heap sono un modo per identificare i nodi scollegati. Come suggerisce il nome, gli snapshot dell'heap mostrano come la memoria è distribuita tra gli oggetti JS e i nodi DOM della tua pagina nel momento dello snapshot.

Per creare uno snapshot, apri DevTools e vai al riquadro Memoria, seleziona il pulsante di opzione Istantanea heap, quindi premi il pulsante Crea istantanea.

acquisisci istantanea heap

L'elaborazione e il caricamento dello snapshot potrebbero richiedere del tempo. Al termine, selezionala dal riquadro di sinistra (denominato HEAP SNAPSHOTS).

Digita Detached nella casella di testo Filtro classe per cercare strutture DOM scollegate.

filtrando i nodi scollegati

Espandi i carati per esaminare un albero staccato.

indagando su un albero staccato

I nodi evidenziati in giallo hanno riferimenti diretti dal codice JavaScript. I nodi evidenziati in rosso non hanno riferimenti diretti. Sono vivi solo perché fanno parte dell'albero del nodo giallo. In generale, conviene concentrarsi sui nodi gialli. Correggi il codice in modo che il nodo giallo non resti attivo più a lungo del necessario ed eliminerai anche i nodi rossi che fanno parte dell'albero del nodo giallo.

Fai clic su un nodo giallo per effettuare ulteriori accertamenti. Nel riquadro Oggetti puoi visualizzare ulteriori informazioni sul codice che lo fa riferimento. Ad esempio, nello screenshot seguente puoi vedere che la variabile detachedTree fa riferimento al nodo. Per correggere questa particolare perdita di memoria, devi studiare il codice che utilizza detachedTree e assicurarti che rimuova il suo riferimento al nodo quando non è più necessario.

indaga su un nodo giallo

Identifica le perdite di memoria heap di JS con gli Spostamenti di allocazione

La sequenza temporale di allocazione è un altro strumento che consente di tenere traccia delle perdite di memoria nell'heap di JS.

Per dimostrare la sequenza temporale di allocazione, considera il seguente codice:

var x = [];

function grow() {
  x.push(new Array(1000000).join('x'));
}

document.getElementById('grow').addEventListener('click', grow);

Ogni volta che viene eseguito il push del pulsante a cui viene fatto riferimento nel codice, all'array x viene aggiunta una stringa di un milione di caratteri.

Per registrare una sequenza temporale di allocazione, apri DevTools, vai al riquadro Profili, seleziona il pulsante di opzione Registra cronologia di allocazione, premi il pulsante Avvia, esegui l'azione che ritieni causi la perdita di memoria, quindi premi il pulsante di interruzione della registrazione (pulsante interrompi la registrazione) quando hai finito.

Mentre registri, controlla se nella sequenza temporale di allocazione vengono visualizzate delle barre blu, come nello screenshot di seguito.

nuove allocazioni

Queste barre blu rappresentano le nuove allocazioni della memoria. Queste nuove allocazioni di memoria sono candidature per perdite di memoria. Puoi eseguire lo zoom su una barra per filtrare il riquadro Costruttore in modo da mostrare solo gli oggetti allocati durante il periodo di tempo specificato.

sequenza temporale di allocazione ingrandita

Espandi l'oggetto e fai clic sul relativo valore per visualizzarne i dettagli nel riquadro Oggetto. Ad esempio, nello screenshot seguente, visualizzando i dettagli dell'oggetto appena allocato, potrai vedere che è stato allocato alla variabile x nell'ambito Window.

dettagli dell&#39;oggetto

Analizzare l'allocazione della memoria in base alla funzione

Utilizza il tipo Allocation Sampling (Campionamento di allocazione) nel riquadro Memory (Memoria) per visualizzare l'allocazione della memoria in base alla funzione JavaScript.

Profiler allocazione dei record

  1. Seleziona il pulsante di opzione Allocation Sampling (Campionamento di allocazione). Se nella pagina è presente un worker, puoi selezionarlo come target di profilazione utilizzando il menu a discesa accanto al pulsante Avvia.
  2. Premi il pulsante Avvia.
  3. Esegui le azioni sulla pagina che vuoi esaminare.
  4. Una volta completate tutte le azioni, premi il pulsante Interrompi.

DevTools mostra un'analisi dell'allocazione della memoria per funzione. La visualizzazione predefinita è Intensa (dal basso verso l'alto) e mostra le funzioni che hanno allocato più memoria nella parte superiore.

Profilo di allocazione

Individua garbage collection frequente

Se la tua pagina viene messa in pausa frequentemente, potrebbero esserci problemi di garbage collection.

Per individuare frequenti garbage collection puoi utilizzare le registrazioni della memoria di Chrome Task Manager o degli Spostamenti. In Task Manager, i valori di Memoria o Memoria JavaScript aumentano e diminuiscono frequentemente rappresentano garbage collection frequenti. Nelle registrazioni degli Spostamenti, i grafici del conteggio dei nodi o degli heap di JS in aumento o in diminuzione indicano frequenti garbage collection.

Una volta identificato il problema, puoi utilizzare la registrazione della sequenza temporale di allocazione per scoprire dove viene allocata la memoria e quali funzioni stanno causando le allocazioni.