Sobes.tech
Middle+

Como identificar a presença de uma fuga de memória ao analisar um dump?

sobes.tech IA

Resposta da IA

Para detectar fugas de memória num dump (ficheiro HPROF), utilizam-se ferramentas que analisam o gráfico de objetos no heap. Passos principais:

  1. Obter o dump de memória:

    • Através do Memory Profiler do Android Studio.
    • Com o comando adb shell dumpheap <nome_do_pacote> /data/local/tmp/dump.hprof.
    • Com a chamada ao sistema Debug.dumpHprofData(filePath).
  2. Analisar o dump:

    • Abrir o dump no Android Studio: no Memory Profiler ou através do menu "Ficheiro" -> "Abrir".
    • Análise de objetos: ordenar objetos por tamanho (Shallow Size, Retained Size) e quantidade de instâncias.
    • Procurar objetos suspeitos: procure classes que deveriam ser destruídas (por exemplo, Activity, Fragment, Contexts) mas têm muitas instâncias ou um Retained Size significativo.
    • Estudar o caminho até ao objeto (Cadeia de Referências): selecione um objeto suspeito e trace o seu caminho até aos objetos raiz (GC roots). Isto mostrará quem mantém a referência, impedindo a recolha de lixo.
    • Procurar referências estáticas: os campos estáticos são frequentemente uma fonte de fugas se armazenarem referências de longa duração a contextos ou vistas.
    • Usar LeakCanary: a biblioteca automatiza a deteção, dump e análise de fugas em tempo de execução, fornecendo uma descrição detalhada do caminho da fuga.
  3. Interpretação dos resultados:

    • Um caminho longo até GC root que contém referências a objetos que deveriam ser destruídos indica um problema.
    • As referências a partir de campos estáticos, AsyncTask, Handlers com atrasos, listeners/callbacks não desregistrados corretamente, ou singletons em atividades ou vistas, são frequentemente a causa de fugas.

Exemplo de análise do caminho até GC root no Android Studio Memory Profiler:

// Exemplo de caminho até GC root que indica uma fuga
// android.app.Activity instância com mDestroyed=true
//   referências a android.widget.LinearLayout
//     referências a android.view.View $ListenerInfo
//       referências a com.example.MyActivity$1 (classe anónima que implementa View.OnClickListener)
//         referências a com.example.MyActivity (referência que provoca a fuga)

Neste exemplo, uma classe anónima (listener de clique no botão) mantém uma referência implícita a MyActivity, embora a atividade já deva estar destruída (mDestroyed=true). Este listener parece estar registado ou retido por outro objeto de longa duração (por exemplo, um campo estático ou um singleton).