Acquisisci un dump dell'heap

Acquisisci un dump dell'heap per vedere quali oggetti della tua app stanno utilizzando la memoria al momento dell'acquisizione e identifica le perdite di memoria o il comportamento di allocazione della memoria che porta a balbuzie, blocchi e persino arresti anomali dell'app. È particolarmente utile eseguire dump dell'heap dopo una sessione utente estesa, quando potrebbero essere visualizzati oggetti ancora in memoria che non dovrebbero più essere presenti.

Questa pagina descrive gli strumenti forniti da Android Studio per raccogliere e analizzare i dump dell'heap. In alternativa, puoi ispezionare la memoria dell'app dalla riga di comando con dumpsys e anche visualizzare gli eventi di raccolta dei rifiuti (GC) in Logcat.

Perché dovresti eseguire il profiling della memoria dell'app

Android fornisce un ambiente di memoria gestita: quando Android stabilisce che la tua app non utilizza più alcuni oggetti, il garbage collector restituisce la memoria inutilizzata all'heap. Il modo in cui Android trova la memoria inutilizzata è in costante miglioramento, ma a un certo punto su tutte le versioni di Android il sistema deve mettere in pausa brevemente il codice. La maggior parte delle volte, le interruzioni sono impercettibili. Tuttavia, se l'app alloca la memoria più velocemente di quanto il sistema possa raccoglierla, l'app potrebbe subire un ritardo mentre il raccoglitore libera memoria sufficiente per soddisfare le tue allocazioni. Il ritardo potrebbe causare l'interruzione dei frame dell'app e provocare un rallentamento visibile.

Anche se la tua app non presenta rallentamenti, se perde memoria, può trattenere questa memoria anche quando è in background. Questo comportamento può rallentare il resto delle prestazioni della memoria del sistema forzando eventi di raccolta del garbage non necessari. Alla fine, il sistema è costretto ad arrestare il processo dell'app per recuperare la memoria. Quando l'utente torna alla tua app, il processo dell'app deve riavviare completamente.

Per informazioni sulle pratiche di programmazione che possono ridurre l'utilizzo della memoria dell'app, leggi l'articolo Gestire la memoria dell'app.

Panoramica dei dump dell'heap

Per acquisire un dump dell'heap, seleziona l'attività Analizza l'utilizzo della memoria (dump dell'heap) (utilizza Profiler: esegui "app" come eseguibile (dati completi)) per acquisire un dump dell'heap. Durante il dump dello heap, la quantità di memoria Java potrebbe aumentare temporaneamente. Questo è normale perché il dump dell'heap si verifica nello stesso processo della tua app e richiede un po' di memoria per raccogliere i dati. Dopo aver acquisito il dump heap, viene visualizzato quanto segue:

L'elenco dei corsi mostra le seguenti informazioni:

  • Allocazioni: numero di allocazioni nell'heap.
  • Dimensioni native: quantità totale di memoria nativa utilizzata da questo tipo di oggetto (in byte). Qui vedrai la memoria per alcuni oggetti allocati in Java perché Android utilizza la memoria nativa per alcune classi del framework, ad esempio Bitmap.

  • Dimensioni ridotte: quantità totale di memoria Java utilizzata da questo tipo di oggetto (in byte).

  • Dimensioni trattenute: dimensioni totali della memoria trattenuta a causa di tutte le istanze di questa classe (in byte).

Utilizza il menu cumulo per filtrare in base a determinati cumuli:

  • Heap dell'app (predefinito): l'heap principale su cui l'app alloca la memoria.
  • Heap di immagini: l'immagine di avvio del sistema, contenente le classi precaricate durante l'avvio. Le allocazioni qui non si spostano né scompaiono.
  • Zygote heap: l'heap copy-on-write da cui viene eseguito il fork di un processo dell'app nel sistema Android.

Utilizza il menu a discesa ordinamento per scegliere come organizzare le allocazioni:

  • Ordina per classe (predefinito): raggruppa tutte le allocazioni in base al nome della classe.
  • Ordina per pacchetto: raggruppa tutte le allocazioni in base al nome del pacchetto.

Utilizza il menu a discesa dei corsi per filtrare i risultati in base a gruppi di corsi:

  • Tutti i moduli (impostazione predefinita): mostra tutti i moduli, inclusi quelli delle librerie e delle dipendenze.
  • Mostra perdite di attività/frammenti: mostra le classi che causano perdite di memoria.
  • Mostra i corsi del progetto: mostra solo i corsi definiti dal progetto.

Fai clic sul nome di un corso per aprire il riquadro Istanza. Ogni istanza elencata include quanto segue:

  • Profondità: il numero più breve di hop da qualsiasi entità principale di Google Cloud all'istanza selezionata.
  • Dimensione nativa: dimensione di questa istanza in memoria nativa. Questa colonna è visibile solo per Android 7.0 e versioni successive.
  • Dimensioni ridotte: dimensioni di questa istanza nella memoria Java.
  • Dimensione residua: dimensione della memoria dominata da questa istanza (in base all'albero dei dominatori).

Fai clic su un'istanza per visualizzare i dettagli dell'istanza, inclusi i campi e i riferimento. I tipi di campi e di riferimento comuni sono tipi strutturati, array e tipi di dati primitivi in Java. Fai clic con il tasto destro del mouse su un campo o un riferimento per passare all'istanza o alla riga associata nel codice sorgente.

  • Campi: mostra tutti i campi di questa istanza.
  • Riferimenti: mostra tutti i riferimenti all'oggetto evidenziato nella scheda Istanza.

Trovare perdite di memoria

Per filtrare rapidamente i componenti che potrebbero essere associati a perdite di memoria, apri il menu a discesa del componente e seleziona Mostra perdite di attività/componenti. Android Studio mostra le classi che ritiene indichino perdite di memoria per le istanze Activity e Fragment nella tua app. I tipi di dati visualizzati dal filtro includono:

  • Istanze Activity che sono state distrutte, ma a cui viene ancora fatto riferimento.
  • Istanze Fragment che non hanno un valore FragmentManager valido, ma a cui viene comunque fatto riferimento.

Tieni presente che il filtro potrebbe generare falsi positivi nelle seguenti situazioni:

  • È stato creato un Fragment, ma non è stato ancora utilizzato.
  • Un Fragment viene memorizzato nella cache, ma non nell'ambito di un FragmentTransaction.

Per cercare le perdite di memoria in modo più manuale, sfoglia gli elenchi di classi e istanze per trovare oggetti con Dimensioni conservate di grandi dimensioni. Cerca le perdite di memoria causate da uno dei seguenti elementi:

  • Riferimenti a lungo termine a Activity, Context, View, Drawable e altri oggetti che potrebbero contenere un riferimento al contenitore Activity o Context.
  • Classi interne non statiche, ad esempio un Runnable, che possono contenere un'istanza Activity.
  • Cache che conservano gli oggetti più a lungo del necessario.

Quando trovi potenziali perdite di memoria, utilizza le schede Campi e Riferimenti in Dettagli istanza per passare all'istanza o alla riga di codice sorgente di tuo interesse.

Attivare le perdite di memoria per i test

Per analizzare l'utilizzo della memoria, devi sottoporre a stress il codice dell'app e provare a forzare le perdite di memoria. Un modo per provocare perdite di memoria nell'app è lasciarla in esecuzione per un po' di tempo prima di ispezionare l'heap. Le perdite potrebbero risalire fino alla parte superiore delle allocazioni nella heap. Tuttavia, più piccolo è il leak, più a lungo devi eseguire l'app per visualizzarlo.

Puoi anche attivare una perdita di memoria in uno dei seguenti modi:

  • Ruota il dispositivo dalla modalità verticale a quella orizzontale e viceversa più volte mentre è in stati di attività diversi. La rotazione del dispositivo può spesso causare la perdita di un oggetto Activity, Context o View da parte di un'app perché il sistema ricrea Activity e, se la tua app contiene un riferimento a uno di questi oggetti altrove, il sistema non può eseguire la raccolta dei rifiuti.
  • Passare dalla tua app a un'altra app in stati di attività diversi. Ad esempio, vai alla schermata Home, quindi torna all'app.

Esportare e importare una registrazione del dump dell'heap

Puoi esportare e importare un file dump heap dalla scheda Registrazioni passate nel profiler. Android Studio salva la registrazione come file .hprof.

In alternativa, per utilizzare un altro analizzatore di file .hprof come jhat, devi convertire il file .hprof dal formato Android al formato file Java SE .hprof. Per convertire il formato del file, utilizza lo strumento hprof-conv fornito nella directory {android_sdk}/platform-tools/. Esegui il comando hprof-conv con due argomenti: il nome file .hprof originale e la posizione in cui scrivere il file .hprof convertito, incluso il nuovo nome file .hprof. Per esempio:

hprof-conv heap-original.hprof heap-converted.hprof