Acquisisci un dump dell'heap

Acquisisci un dump dell'heap per vedere quali oggetti nella tua app stanno consumando memoria al momento dell'acquisizione e identificare le perdite di memoria o il comportamento di allocazione della memoria che porta a stuttering, blocchi e persino arresti anomali dell'app. È particolarmente utile eseguire i dump dell'heap dopo una sessione utente estesa, quando potrebbe mostrare 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 visualizzare anche gli eventi di garbage collection (GC) in Logcat.

Perché eseguire la profilazione della memoria dell'app

Android provides a managed memory environment—when Android determines that your app is no longer using some objects, the garbage collector releases the unused memory back to the heap. Il modo in cui Android trova la memoria inutilizzata viene costantemente migliorato, ma a un certo punto in tutte le versioni di Android il sistema deve mettere in pausa brevemente il codice. Nella maggior parte dei casi, le pause sono impercettibili. Tuttavia, se la tua app alloca la memoria più velocemente di quanto il sistema possa raccoglierla, l'app potrebbe subire ritardi mentre il raccoglitore libera memoria sufficiente per soddisfare le allocazioni. Il ritardo potrebbe causare la perdita di frame e un rallentamento visibile dell'app.

Anche se la tua app non presenta rallentamenti, se perde memoria, può conservarla anche quando è in background. Questo comportamento può rallentare le prestazioni della memoria del resto del sistema forzando eventi di garbage collection non necessari. Alla fine, il sistema è costretto a terminare il processo dell'app per recuperare la memoria. Poi, quando l'utente torna all'app, il processo dell'app deve essere riavviato completamente.

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

Panoramica del dump dell'heap

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

La visualizzazione Dump dell'heap in Android Studio Profiler.

L'elenco delle classi mostra le seguenti informazioni:

  • Allocazioni: numero di allocazioni nell'heap.
  • Dimensione nativa: 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, come Bitmap.

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

  • Dimensione mantenuta: dimensione totale della memoria mantenuta a causa di tutte le istanze di questa classe (in byte).

Utilizza il menu dell'heap per filtrare determinati heap:

  • Heap dell'app (impostazione predefinita): l'heap principale su cui l'app alloca la memoria.
  • Heap dell'immagine: l'immagine di avvio del sistema, contenente le classi precaricate durante l'avvio. Le allocazioni qui non vengono mai spostate o eliminate.
  • Heap Zygote: l'heap copy-on-write da cui viene generato un processo dell'app in nel sistema Android.

Utilizza il menu a discesa di disposizione per scegliere come disporre le allocazioni:

  • Disponi per classe (impostazione predefinita): raggruppa tutte le allocazioni in base al nome della classe.
  • Disponi per pacchetto: raggruppa tutte le allocazioni in base al nome del pacchetto.

Utilizza il menu a discesa della classe per filtrare i gruppi di classi:

  • Tutte le classi (impostazione predefinita): mostra tutte le classi, incluse quelle di librerie e dipendenze.
  • Mostra perdite di attività/fragment: mostra le classi che causano perdite di memoria.
  • Mostra classi di progetto: mostra solo le classi definite dal tuo progetto.

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

  • Profondità: il numero minimo di hop da qualsiasi root GC all'istanza selezionata.
  • Dimensione nativa: dimensione di questa istanza nella memoria nativa. Questa colonna è visibile solo per Android 7.0 e versioni successive.
  • Dimensione superficiale: dimensione di questa istanza nella memoria Java.
  • Dimensione mantenuta: 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 Riferimenti. I tipi di campi e riferimenti 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 in questa istanza.
  • Riferimenti: mostra ogni riferimento all'oggetto evidenziato nella scheda Istanza.
Le visualizzazioni Istanze, Campi e Riferimenti nella finestra dello strumento Dump dell'heap.

Trovare perdite di memoria

Per filtrare rapidamente le classi che potrebbero essere associate a perdite di memoria, apri il menu a discesa della classe e seleziona Mostra perdite di attività/fragment. Android Studio mostra le classi che ritiene indichino perdite di memoria per le istanze Activity e Fragment nella tua app.

Per cercare le perdite di memoria in modo più manuale, sfoglia gli elenchi di classi e istanze per trovare gli oggetti con una Dimensione mantenuta elevata. Cerca le perdite di memoria causate da uno dei seguenti elementi:

  • Riferimenti di lunga durata a Activity o Context che possono causare la perdita del grafico di composizione Compose ospitato (ad esempio ComposeView e i relativi composable secondari).
  • Perdita di oggetti di stato di Jetpack Compose (MutableState), titolari di stato o lambda che acquisiscono Context.
  • Dimenticare di liberare spazio per i listener o gli osservatori nel blocco onDispose di un DisposableEffect.
  • Classi interne non statiche, come a Runnable, che possono contenere un'Activity istanza.
  • Cache che contengono oggetti più a lungo del necessario.

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

Attivare le perdite di memoria per i test

Per analizzare la memoria utilizzata, devi stressare il codice dell'app e provare a forzare le perdite di memoria. Un modo per provocare perdite di memoria nella tua app è lasciarla in esecuzione per un po' di tempo prima di ispezionare l'heap. Le perdite potrebbero arrivare fino alla parte superiore delle allocazioni nell'heap. Tuttavia, minore è la perdita, più a lungo devi eseguire l'app per vederla.

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

  • Ruota il dispositivo da verticale a orizzontale e viceversa più volte in diversi stati di attività. La rotazione del dispositivo può spesso causare la perdita di un Activity (e di conseguenza del relativo albero dell'interfaccia utente Compose ospitato e degli alberi di stato associati) se l'app contiene un riferimento a Activity o Context all'interno di operazioni asincrone o titolari di stato.
  • Passa da un'app all'altra in diversi stati di attività. Ad esempio, vai alla schermata Home, quindi torna alla tua app.

Esportare e importare una registrazione del dump dell'heap

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

In alternativa, per utilizzare un analizzatore di file .hprof diverso, come jhat, devi convertire il file .hprof dal formato Android al formato di file .hprof Java SE. 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. Ad esempio:

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

Risorse aggiuntive