Risolvere i problemi di memoria

Scopri come utilizzare Chrome e DevTools per trovare problemi di memoria che influiscono sulle prestazioni della pagina, tra cui perdite di memoria, aumento inutilmente elevato della memoria e raccolte dei rifiuti frequenti.

Riepilogo

  • Scopri quanta memoria utilizza la tua pagina con il Task Manager di Chrome.
  • Visualizza l'utilizzo della memoria nel tempo con le registrazioni di Spostamenti.
  • Identifica gli alberi DOM scollegati (una causa comune di perdite di memoria) con gli istantanei dell'heap.
  • Scopri quando viene allocata nuova memoria nell'heap JS con le registrazioni della sequenza temporale di allocazione.
  • Identifica gli elementi scollegati conservati dal riferimento JavaScript.

Panoramica

In linea con lo spirito del modello di prestazioni RAIL, l'obiettivo dei tuoi sforzi per migliorare il rendimento dovrebbe essere rivolto ai tuoi 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. Potrebbe trattarsi di un 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 un aumento eccessivo della memoria. Il ballooning della memoria si verifica quando una pagina utilizza più memoria del necessario per una velocità ottimale.
  • Il rendimento di una pagina è in ritardo o sembra essere in pausa di frequente. Potrebbe trattarsi di un sintomo di raccolte di rifiuti frequenti. La raccolta dei rifiuti avviene quando il browser recupera la memoria. È il browser a decidere quando ciò accade. Durante le raccolte, l'esecuzione di tutti gli script viene messa in pausa. Pertanto, se il browser svolge spesso la raccolta dei rifiuti, l'esecuzione dello script verrà messa in pausa molto spesso.

Aumento inutilmente elevato della memoria: quanto è "troppo"?

Una perdita di memoria è facile da definire. Se un sito utilizza progressivamente sempre più memoria, significa che hai una perdita. Tuttavia, l'aumento inutilmente elevato della memoria è un po' più difficile da individuare. Che cosa si intende per "utilizzo di troppa memoria"?

Non ci sono dati precisi, perché dispositivi e browser diversi hanno funzionalità diverse. La stessa pagina che funziona senza problemi su uno smartphone di fascia alta potrebbe bloccarsi su uno smartphone di fascia bassa.

L'importante è utilizzare il modello RAIL e concentrarti sugli utenti. Scopri quali dispositivi sono apprezzati dai 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.

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

Utilizza Task Manager di Chrome come punto di partenza per la ricerca del problema di memoria. Task Manager è un monitor in tempo reale che ti dice quanta memoria sta utilizzando una pagina.

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

    Aprire il Task Manager.

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

    Attivazione della memoria JS nell'intestazione di Task Manager.

Queste due colonne forniscono informazioni diverse su come la tua pagina utilizza la memoria:

  • La colonna Impronta della memoria rappresenta la memoria del sistema operativo. I nodi DOM vengono memorizzati nella memoria del sistema operativo. Se questo valore è in aumento, significa che vengono creati nodi DOM.
  • La colonna Memoria JavaScript rappresenta l'heap JS. Questa colonna contiene due valori. Il valore che ti interessa è il numero in tempo reale (il numero tra parentesi). Il numero in tempo reale rappresenta la quantità di memoria utilizzata dagli oggetti raggiungibili nella pagina. Se questo numero è in aumento, significa che vengono creati nuovi oggetti o che quelli esistenti stanno aumentando.

    Task Manager con l'intestazione della memoria JavaScript attivata.

Visualizzare le perdite di memoria con le registrazioni del rendimento

Puoi anche utilizzare il riquadro Rendimento come altro punto di partenza per la tua indagine. Il riquadro Rendimento ti aiuta a visualizzare l'utilizzo della memoria di una pagina nel tempo.

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

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

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 si fa riferimento nel codice, vengono aggiunti diecimila nodi div al corpo del documento e una stringa di un milione di caratteri x viene inserita nell'array x. L'esecuzione di questo codice produce una registrazione della cronologia come lo screenshot seguente:

Un semplice esempio di crescita.

Innanzitutto, una spiegazione dell'interfaccia utente. Il grafico HEAP nel riquadro Panoramica (sotto 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 nel grafico HEAP nel riquadro Panoramica), documenti, nodi DOM, ascoltatori e memoria GPU. Se disattivi una casella di controllo, questa viene nascosta nel grafico.

Ora, un'analisi del codice rispetto allo screenshot. Se guardi 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 numero di nodi sia una chiamata a grow(). Il grafico della heap JS (il grafico blu) non è così semplice. In linea con le best practice, il primo calo è in realtà una raccolta dei rifiuti forzata (ottenuta premendo il pulsante Raccogli rifiuti). Man mano che la registrazione procede, puoi notare picchi nelle dimensioni dell'heap JS. Questo è normale e previsto: il codice JavaScript crea i nodi DOM a ogni clic del pulsante e svolge molto lavoro quando crea la stringa di un milione di caratteri. L'aspetto fondamentale è che l'heap JS termina in un punto più alto rispetto a quello di inizio ("inizio" qui indica il punto successivo alla raccolta dei rifiuti forzata). Nella vita reale, se noti questo andamento di aumento delle dimensioni dello heap JS o del nodo, potrebbe indicare una perdita di memoria.

Scoprire le perdite di memoria dell'albero DOM scollegato con le istantanee heap

Un nodo DOM può essere sottoposto a garbage collection solo se non sono presenti riferimenti al nodo stesso nella struttura DOM della pagina o nel codice JavaScript. Un nodo viene definito "scollegato" quando viene rimosso dall'albero DOM, ma alcuni script JavaScript fanno ancora riferimento a questo nodo. I nodi DOM scollegati sono una causa comune di perdite di memoria. Questa sezione spiega come utilizzare i profiler dell'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 fa riferimento il codice, viene creato un nodo ul con dieci elementi secondari li. Questi nodi vengono richiamati dal codice, ma non esistono nella struttura a albero DOM, pertanto sono scollegati.

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

Per creare uno snapshot, apri DevTools e vai al pannello Memoria, seleziona il pulsante di opzione Snapshot dell'heap e poi premi il pulsante Acquisisci snapshot.

Pulsante di opzione Genera istantanea heap selezionato.

L'elaborazione e il caricamento dell'istantanea potrebbero richiedere del tempo. Al termine, selezionalo dal riquadro a sinistra (chiamato Istantanee dell'heap).

Digita Detached nella casella di immissione Filtro classi per cercare alberi DOM scollegati.

Filtro per i nodi scollegati.

Espandi i simboli di punteggiatura per esaminare un albero scollegato.

Indagine su un albero staccato.

Fai clic su un nodo per esaminarlo ulteriormente. Nel riquadro Oggetti puoi visualizzare ulteriori informazioni sul codice che fa riferimento all'oggetto. 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 riferimento al nodo quando non è più necessario.

Indagine su un nodo scollegato.

Identificare le perdite di memoria dell'heap JS con le sequenze temporali allocazioni

La Cronologia allocazione è un altro strumento che può aiutarti a individuare perdite di memoria nell'heap JS.

Per dimostrare la Cronologia dell'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 premuto il pulsante a cui si fa riferimento nel codice, viene aggiunta all'array x una stringa di un milione di caratteri.

Per registrare una Cronologia delle allocazioni, apri DevTools, vai al riquadro Memoria, seleziona il pulsante di opzione Allocazioni nella cronologia, premi il pulsante Registra , esegui l'azione che sospetti stia causando la perdita di memoria e, al termine, premi il pulsante Interrompi registrazione.

Durante la registrazione, controlla se nella Sequenza temporale dell'allocazione vengono visualizzate barre blu, come nello screenshot seguente.

Nuove allocazioni nella cronologia del rendimento.

Queste barre blu rappresentano le nuove allocazioni di memoria. Queste nuove allocazioni di memoria sono candidate per le perdite di memoria. Puoi aumentare lo zoom su una barra per filtrare il riquadro Costruttore in modo da visualizzare solo gli oggetti che sono stati allocati durante il periodo di tempo specificato.

Una sequenza temporale dell&#39;allocazione con zoom.

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

Dettagli dell&#39;oggetto di un array di stringhe.

Esaminare l'allocazione della memoria per funzione

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

Profiler del campionamento delle allocazioni nel riquadro Memoria.

  1. Seleziona il pulsante di opzione Campionamento dell'allocazione. Se nella pagina è presente un worker, puoi selezionarlo come target di profilazione dalla finestra Seleziona istanza VM JavaScript.
  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 dettagliata dell'allocazione della memoria per funzione. La visualizzazione predefinita è Intensive (dal basso verso l'alto), che mostra in alto le funzioni che hanno allocato la maggior parte della memoria.

Pagina dei risultati del profilo di allocazione.

Identificare gli oggetti conservati dal riferimento JS

Il profilo Elementi scollegati mostra gli elementi scollegati che rimangono perché a cui viene fatto riferimento dal codice JavaScript.

Registra un profilo Elementi scollegati per visualizzare i nodi HTML esatti e il conteggio dei nodi.

Esempio di profilo di elementi scollegati.

Individuare raccolte frequenti dei rifiuti

Se la pagina sembra essere in pausa di frequente, potresti avere problemi di raccolta dei rifiuti.

Puoi utilizzare il Task Manager di Chrome o le registrazioni della memoria di Spostamenti per individuare raccolte di dati spazzatura frequenti. In Task Manager, i valori di Memoria o Memoria JavaScript che aumentano e diminuiscono di frequente rappresentano raccolte di rifiuti frequenti. Nelle registrazioni di Spostamenti, i grafici con conteggi di heap o nodi JS in aumento e in calo indicano raccolte di rifiuti frequenti.

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