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:
-
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).
-
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 Sizesignificativo. - 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.
-
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).