Sobes.tech
Middle+

Come determinare la presenza di una perdita di memoria analizzando un dump?

sobes.tech AI

Risposta dell'AI

Per rilevare perdite di memoria in un dump (file HPROF), vengono utilizzati strumenti che analizzano il grafo degli oggetti nell'heap. Passaggi principali:

  1. Ottenere il dump di memoria:

    • Tramite il Memory Profiler di Android Studio.
    • Con il comando adb shell dumpheap <nome_pacchetto> /data/local/tmp/dump.hprof.
    • Con la chiamata di sistema Debug.dumpHprofData(filePath).
  2. Analizzare il dump:

    • Aprire il dump in Android Studio: nel Memory Profiler o tramite il menu "File" -> "Apri".
    • Analisi degli oggetti: ordinare gli oggetti per dimensione (Shallow Size, Retained Size) e numero di istanze.
    • Cercare oggetti sospetti: cercare classi che dovrebbero essere distrutte (ad esempio, Activity, Fragment, Contexts) ma hanno molte istanze o un Retained Size significativo.
    • Studiare il percorso verso l'oggetto (Reference Chain): selezionare un oggetto sospetto e tracciare il suo percorso verso gli oggetti radice (GC roots). Questo mostrerà chi mantiene il riferimento, impedendo la raccolta dei rifiuti.
    • Cercare riferimenti statici: i campi statici sono spesso una fonte di perdite se memorizzano riferimenti di lunga durata a contesti o viste.
    • Usare LeakCanary: la libreria automatizza il rilevamento, il dump e l'analisi delle perdite in tempo reale, fornendo una descrizione dettagliata del percorso della perdita.
  3. Interpretazione dei risultati:

    • Un percorso lungo verso GC root che contiene riferimenti a oggetti che dovrebbero essere distrutti indica un problema.
    • Riferimenti da campi statici, AsyncTask, Handler con ritardi, listener/callback non disdetti correttamente, o singleton in attività o viste sono spesso causa di perdite.

Esempio di analisi del percorso verso GC root in Android Studio Memory Profiler:

// Esempio di percorso verso GC root che indica una perdita
// android.app.Activity istanza con mDestroyed=true
//   riferimenti a android.widget.LinearLayout
//     riferimenti a android.view.View $ListenerInfo
//       riferimenti a com.example.MyActivity$1 (classe anonima che implementa View.OnClickListener)
//         riferimenti a com.example.MyActivity (riferimento che causa la perdita)

In questo esempio, una classe anonima (listener del clic del pulsante) mantiene un riferimento implicito a MyActivity, anche se l'attività dovrebbe essere già distrutta (mDestroyed=true). Questo listener sembra essere registrato o trattenuto da un altro oggetto di lunga durata (ad esempio, un campo statico o un singleton).