Acquisisci un dump dell'heap

Acquisisci un dump dell'heap per vedere quali oggetti nella tua app utilizzano la memoria al momento dell'acquisizione e identificare perdite di memoria o un comportamento di allocazione della memoria che porta a stuttering, blocchi e persino arresti anomali dell'app. È particolarmente utile eseguire dump dell'heap dopo una sessione utente prolungata, 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 esaminare la memoria dell'app dalla riga di comando con dumpsys e anche visualizzare gli eventi di Garbage Collection (GC) in Logcat.

Perché dovresti profilare la memoria della tua app

Android fornisce un ambiente di memoria gestita. Quando Android determina che la tua app non utilizza più alcuni oggetti, il garbage collector rilascia la memoria inutilizzata nell'heap. Il modo in cui Android trova la memoria inutilizzata è in costante miglioramento, 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 memoria più velocemente di quanto il sistema possa raccoglierla, potrebbe verificarsi un ritardo mentre il raccoglitore libera memoria sufficiente per soddisfare le tue allocazioni. Il ritardo potrebbe causare la perdita di frame e un rallentamento visibile nell'app.

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

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

Panoramica del dump dell'heap

Per acquisire un dump dell'heap, seleziona l'attività Analizza utilizzo memoria (dump dell'heap) (utilizza Profiler: run 'app' as debuggable (complete data)) per acquisire un dump dell'heap. Durante il dump 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 Heap Dump in Android Studio Profiler.

L'elenco dei corsi mostra le seguenti informazioni:

  • Allocazioni: numero di allocazioni nell'heap.
  • Dimensioni native: la 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 superficiali: quantità totale di memoria Java utilizzata da questo tipo di oggetto (in byte).

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

Utilizza il menu della pila per filtrare in base a determinate pile:

  • 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 creato un fork del processo di un'app nel sistema Android.

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

  • Organizza per corso (impostazione predefinita): raggruppa tutte le assegnazioni in base al nome del corso.
  • Organizza 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 delle librerie e delle dipendenze.
  • Mostra perdite di attività/frammenti: mostra le classi che causano perdite di memoria.
  • Mostra classi del 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 radice 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 (come da 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 Heap Dump.

Rilevare bitmap duplicati

Puoi anche rilevare bitmap ridondanti nella visualizzazione Heap Dump a partire da Android Studio Narwhal 4.

Ecco come trovarli:

  1. Apri la scheda Profiler in Android Studio
  2. Fai clic su Heap Dump (o Analizza utilizzo memoria) e poi su Registra per acquisire uno snapshot dello stato attuale della memoria della tua app.
  3. Scansiona i risultati dell'analisi per individuare il triangolo giallo di avviso ⚠️, che Android Studio utilizza per segnalare le bitmap duplicate memorizzate più volte.
    • In alternativa, vai all'intestazione del profiler, scegli Filtra per: e seleziona l'impostazione Bitmap duplicati.
  4. Fai clic su una voce segnalata per aprire il riquadro Anteprima bitmap, che ti consente di vedere esattamente quale immagine è la recidiva.
  5. Utilizza questa conferma visiva per individuare la logica di caricamento ridondante nel codice e implementare una strategia di memorizzazione nella cache migliore.
Cerca bitmap duplicati utilizzando il triangolo di avviso giallo ⚠️.

Trovare perdite di memoria

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

Per cercare perdite di memoria in modo più manuale, sfoglia gli elenchi di classi e istanze per trovare oggetti con un valore elevato di Dimensioni mantenute. Cerca perdite di memoria causate da uno dei seguenti problemi:

  • Riferimenti di lunga durata a Activity o Context che possono divulgare il grafico di composizione di Compose ospitato (ad esempio ComposeView e i relativi composable secondari).
  • Perdita di oggetti State di Jetpack Compose (MutableState), titolari dello stato o espressioni lambda che acquisiscono Context.
  • Dimenticare di eliminare gli ascoltatori o gli osservatori nel blocco onDispose di un DisposableEffect.
  • 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 interesse.

Attivare perdite di memoria per i test

Per analizzare la memoria utilizzata, devi sottoporre a stress 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, più piccola è la perdita, più a lungo devi eseguire l'app per visualizzarla.

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 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 e degli alberi di stato associati) se la tua app contiene un riferimento a Activity o Context all'interno di operazioni asincrone o contenitori di stato.
  • Passa da un'app all'altra in diversi stati di attività. 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 di dump dell'heap dalla scheda Registrazioni passate nel profiler. Android Studio salva la registrazione come file .hprof.

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