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:
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.
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
ActivityoContextche possono causare la perdita del grafico di composizione Compose ospitato (ad esempioComposeViewe i relativi composable secondari). - Perdita di oggetti di stato di Jetpack Compose (
MutableState), titolari di stato o lambda che acquisisconoContext. - Dimenticare di liberare spazio per i listener o gli osservatori nel blocco
onDisposedi unDisposableEffect. - Classi interne non statiche, come a
Runnable, che possono contenere un'Activityistanza. - 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 aActivityoContextall'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