Risolvere i problemi di memoria

Kayce Basques
Kayce Basques

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

Riepilogo

  • Scopri quanta memoria viene attualmente utilizzata dalla pagina con Task Manager di Chrome.
  • Visualizza l'utilizzo della memoria nel tempo con le registrazioni degli Spostamenti.
  • Identifica alberi DOM scollegati (una causa comune di perdite di memoria) con gli snapshot dell'heap.
  • Scopri quando viene allocata nuova memoria nell'heap JS con le registrazioni della sequenza temporale di allocazione.

Panoramica

Nello spirito del modello di prestazioni RAIL, l'obiettivo delle tue attività di performance deve essere quello degli utenti.

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

  • Il rendimento di una pagina peggiora progressivamente nel tempo. Questo è probabilmente un sintomo di una perdita di memoria. Una perdita di memoria si verifica quando un bug nella pagina fa sì che la pagina utilizzi sempre più memoria nel corso del tempo.
  • Il rendimento di una pagina è costantemente scadente. Questo è probabilmente un sintomo di gonfiore della memoria. Il sovraccarico di memoria si verifica quando una pagina utilizza più memoria di quella necessaria per una velocità ottimale.
  • Il rendimento di una pagina subisce un ritardo o sembra essere in pausa frequentemente. Questo probabilmente è un sintomo della garbage collection frequenti. La garbage collection avviene quando il browser recupera memoria. È il browser a decidere quando deve verificarsi questa situazione. Durante le raccolte, l'esecuzione di tutti gli script viene messa in pausa. Quindi, se il browser raccoglie molti rifiuti, l'esecuzione dello script verrà spesso messa in pausa.

Memoria gonfia: quanto è "troppo"?

Una perdita di memoria è facile da definire. Se un sito utilizza progressivamente una quantità sempre maggiore di memoria, significa che si è verificata una perdita. Ma il gonfiore della memoria è un po' più difficile da fissare. Cosa si intende con "uso di troppa memoria"?

Non ci sono numeri reali, perché i vari dispositivi e browser hanno capacità diverse. La stessa pagina che viene eseguita senza problemi su uno smartphone di fascia alta potrebbe arrestarsi in modo anomalo su uno smartphone di fascia bassa.

La chiave qui è utilizzare il modello RAIL e concentrarsi sugli utenti. Scopri quali sono i dispositivi più diffusi tra i tuoi utenti, quindi testa la tua pagina su tali dispositivi. Se l'esperienza è costantemente scadente, è possibile che la pagina abbia superato le capacità di memoria dei dispositivi.

Monitorare l'utilizzo della memoria in tempo reale con il Task Manager di Chrome

Utilizza Gestione attività di Chrome come punto di partenza per gli accertamenti in merito ai problemi di memoria. Task Manager è un monitoraggio in tempo reale che mostra la quantità di memoria attualmente in uso in 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 la memoria JavaScript.

    Attivazione della memoria JS

Queste due colonne forniscono 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 JS. Questa colonna contiene due valori. Il valore che ti interessa è il numero pubblicato (il numero tra parentesi). Il numero in tempo reale rappresenta la quantità di memoria utilizzata dagli oggetti raggiungibili sulla pagina. Se questo numero aumenta, significa che vengono creati nuovi oggetti o che gli oggetti esistenti stanno crescendo.

Visualizza le perdite di memoria con le registrazioni delle prestazioni

Puoi utilizzare il riquadro Rendimento anche come punto di partenza della tua indagine. Il riquadro Prestazioni ti consente di visualizzare la memoria utilizzata da una pagina nel tempo.

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

Per dimostrare le registrazioni con 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 si preme il pulsante a cui si fa riferimento nel codice, al corpo del documento vengono aggiunti diecimila nodi div e una stringa di un milione di caratteri x viene inviata all'array x. L'esecuzione di questo codice produce una registrazione della sequenza temporale come nello screenshot seguente:

esempio di crescita semplice

Innanzitutto, una spiegazione dell'interfaccia utente. Il grafico HEAP nel riquadro Panoramica (sotto a NET) rappresenta l'heap JS. Sotto il riquadro Panoramica si trova 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, la casella di controllo viene nascosta dal grafico.

Ora confrontiamo il codice con lo screenshot. Se osservi il contatore di nodi (il grafico verde) puoi vedere che corrisponde perfettamente al codice. Il numero di nodi aumenta in passi discreti. Puoi presumere che ogni aumento del conteggio dei nodi sia una chiamata a grow(). Il grafico heap JS (il grafico blu) non è così semplice. In linea con le best practice, il primo calo è in realtà una garbage collection forzata (ottenuta premendo il pulsante Raccogli i rifiuti). Man mano che la registrazione avanza, puoi vedere che le dimensioni dello heap JS registrano dei picchi. Questo è normale e previsto: il codice JavaScript crea nodi DOM a ogni clic su un pulsante e lavora molto quando crea la stringa di un milione di caratteri. La cosa fondamentale qui è il fatto che l'heap JS termina più in alto di quanto è iniziato (l'"inizio" qui è il punto dopo la garbage collection forzata). Nel mondo reale, se vedessi questo modello di aumento della dimensione heap JS o della dimensione dei nodi, potrebbe significare una perdita di memoria.

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

Un nodo DOM può essere garbage collection solo quando non vi sono riferimenti nell'albero DOM della pagina o nel codice JavaScript. Un nodo viene definito "scollegato" quando viene rimosso dalla struttura DOM, ma in parte JavaScript lo fa ancora riferimento. I nodi DOM scollegati sono una causa comune di perdite di memoria. Questa sezione illustra 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);

Se fai clic sul pulsante a cui si fa riferimento nel codice, viene creato un nodo ul con dieci li secondari. Il codice fa riferimento a questi nodi, ma non esistono nella struttura DOM, quindi sono scollegati.

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

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

acquisisci istantanea heap

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

Digita Detached nella casella di testo Filtro corso per cercare alberi DOM scollegati.

filtro per nodi scollegati

Espandi i carati per esaminare un albero staccato.

indagare 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, dovresti concentrarti sui nodi gialli. Correggi il codice in modo che il nodo giallo non rimanga attivo per più tempo del necessario e ti sbarazzerai anche dei nodi rossi che fanno parte della struttura ad albero del nodo giallo.

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

che analizza un nodo giallo

Identifica le perdite di memoria heap JS con le tempistiche di allocazione

La sequenza temporale di allocazione è un altro strumento che può aiutarti a tenere traccia delle perdite di memoria nel tuo heap JS.

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

var x = [];

function grow() {
  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, viene aggiunta una stringa di un milione di caratteri all'array x.

Per registrare una sequenza temporale di allocazione, apri DevTools, vai al riquadro Profili, seleziona il pulsante di opzione Registra sequenze di allocazione, premi il pulsante Avvia, esegui l'azione che sospetti causi la perdita di memoria, quindi premi il pulsante Interrompi registrazione (pulsante interrompi registrazione) al termine.

Durante la registrazione, controlla se nella sequenza temporale di allocazione vengono visualizzate delle barre blu, come nello screenshot di seguito.

nuove allocazioni

Le barre blu rappresentano nuove allocazioni di memoria. Queste nuove allocazioni di memoria sono ideali per le perdite di memoria. Puoi eseguire lo zoom su una barra per filtrare il riquadro Costruttore in modo da visualizzare 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 visualizzare ulteriori dettagli nel riquadro Oggetto. Ad esempio, nello screenshot di seguito puoi vedere che sono stati allocati l'oggetto appena allocato per vedere che è stato allocato alla variabile x nell'ambito Window.

dettagli oggetto

Esamina l'allocazione della memoria per funzione

Utilizza il tipo Campionamento di allocazione nel riquadro Memoria per visualizzare l'allocazione della memoria tramite la funzione JavaScript.

Profiler allocazione dei record

  1. Seleziona il pulsante di opzione Allocation Sampling (Campionamento per l'allocazione). Se nella pagina è presente un worker, puoi selezionarlo come destinazione della 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. Premi il pulsante Interrompi al termine di tutte le azioni.

DevTools mostra un'analisi dell'allocazione della memoria per funzione. La visualizzazione predefinita è Intensa (dal basso verso l'alto), che mostra le funzioni che hanno allocato la maggior quantità di memoria in alto.

Profilo di allocazione

Individuare le garbage collection frequenti

Se la tua pagina sembra essere messa in pausa frequentemente, potresti avere problemi di garbage collection.

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

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