Capture um heap dump para ver quais objetos do app estão usando memória no momento da captura e identificar vazamentos de memória ou comportamentos de alocação de memória que levam a oscilações, travamentos e até falhas no app. É especialmente útil fazer heap dumps após uma sessão de usuário prolongada, quando ele pode mostrar objetos ainda na memória que não deveriam mais estar lá.
Nesta página, descrevemos as ferramentas que o Android Studio oferece para coletar e
analisar heap dumps. Como alternativa, você pode inspecionar a memória do app na
linha de comando com dumpsys e também
ver eventos de coleta de lixo (GC, na sigla em inglês) no Logcat.
Por que é necessário criar o perfil da memória do app
O Android oferece um ambiente de memória gerenciado: quando determina que o app deixou de usar alguns objetos, o coletor de lixo libera a memória não utilizada para a heap. A forma como o Android encontra memória não utilizada é melhorada constantemente. No entanto, em todas as versões do Android, o sistema precisa interromper brevemente seu código em algum momento. Na maioria das vezes, as pausas são imperceptíveis. No entanto, se o app alocar memória mais rápido do que o sistema pode coletar, ele poderá ser atrasado enquanto o coletor libera memória suficiente para atender às alocações. Esse atraso pode fazer com que o app pule frames e gere uma lentidão visível.
Ainda que não exiba essa lentidão, se o app vazar memória, pode reter essa memória mesmo quando estiver em segundo plano. Esse comportamento pode diminuir o resto da performance de memória do sistema ao forçar eventos desnecessários de coleta de lixo. Com o tempo, o sistema será forçado a encerrar o processo do aplicativo para recuperar a memória. Quando o usuário retornar ao app, o processo precisará ser reiniciado completamente.
Para informações sobre práticas de programação que podem reduzir o uso de memória do app, leia [Gerenciar a memória do seu app]memory.
Visão geral do heap dump
Para capturar um heap dump, selecione a tarefa Analyze Memory Usage (Heap Dump) (use Profiler: run 'app' as debuggable (complete data)). Durante o despejo de heap, a quantidade de memória do Java pode aumentar temporariamente. Isso é normal porque o heap dump ocorre no mesmo processo do app e precisa de memória para coletar os dados. Depois de capturar o heap dump, você verá o seguinte:
A lista de turmas mostra as seguintes informações:
- Allocations: número de alocações na heap.
Native Size: quantidade total de memória nativa usada por esse tipo de objeto (em bytes). Você vai ver a memória aqui para alguns objetos alocados em Java porque o Android usa memória nativa para algumas classes de framework, como
Bitmap.Tamanho superficial: quantidade total de memória Java usada por esse tipo de objeto (em bytes).
Retained Size: tamanho retido total da memória devido a todas as instâncias dessa classe (em bytes).
Use o menu de heap para filtrar determinados heaps:
- App heap (padrão): a heap principal na qual o app aloca memória.
- Image heap: a imagem de inicialização do sistema, que contém as classes pré-carregadas durante o tempo de inicialização. As alocações aqui nunca são movidas ou removidas.
- Zygote heap: a heap copy-on-write em que um processo do app é ramificado do sistema Android.
Use o menu suspenso de organização para escolher como organizar as alocações:
- Arrange by class (padrão): agrupa as alocações com base no nome da classe.
- Arrange by package: agrupa as alocações com base no nome do pacote.
Use o menu suspenso de classes para filtrar por grupos de classes:
- All classes (padrão): mostra todas as classes, incluindo as de bibliotecas e dependências.
- Show activity/fragment leaks: mostra as classes que estão causando vazamentos de memória.
- Show project classes: mostra apenas as classes definidas pelo projeto.
Clique no nome de uma classe para abrir o painel Instance. Cada instância listada inclui o seguinte:
- Depth: o menor número de saltos de qualquer raiz de GC até a instância selecionada.
- Native Size: o tamanho da instância na memória nativa. Essa coluna fica visível apenas para o Android 7.0 e versões mais recentes.
- Shallow Size: o tamanho da instância na memória Java.
- Tamanho retido: o tamanho da memória dominada por essa instância, de acordo com a árvore dominante.
Clique em uma instância para mostrar os Detalhes da instância, incluindo os Campos
e as Referências. Os tipos comuns de campo e referência são tipos estruturados
,
matrizes
e tipos de dados primitivos
em Java. Clique com o botão direito do mouse em um campo ou referência para acessar a instância ou
linha associada no código-fonte.
- Campos: mostra todos os campos nessa instância.
- References: mostra todas as referências ao objeto destacado na guia Instance.
Detectar bitmaps duplicados
Também é possível detectar bitmaps redundantes na visualização de heap dump a partir do Android Studio Narwhal 4.
Veja como encontrá-los:
- Abra a guia "Profiler" no Android Studio.
- Clique em Heap Dump (ou Analyze Memory Usage) e em "Record" para capturar um instantâneo do estado atual do uso da memória do app.
- Procure o triângulo de aviso amarelo ⚠️ nos resultados da análise, que
o Android Studio usa para sinalizar bitmaps duplicados que estão sendo armazenados várias vezes.
- Como alternativa, navegue até o cabeçalho do criador de perfil, escolha Filter by: e selecione a configuração Duplicate Bitmaps.
- Clique em qualquer entrada sinalizada para abrir o painel Bitmap Preview, que permite ver exatamente qual imagem é a infratora reincidente.
- Use essa confirmação visual para rastrear a lógica de carregamento redundante no código e implementar uma estratégia de armazenamento em cache melhor.
Encontrar vazamentos de memória
Para filtrar rapidamente as classes que podem estar associadas a vazamentos de memória, abra
o menu suspenso de classes e selecione Show activity/fragment leaks. O Android Studio
mostra classes que ele considera como vazamentos de memória em instâncias de
Activity e
Fragment do seu app.
Para procurar vazamentos de memória de forma mais manual, navegue pelas listas de classes e instâncias para encontrar objetos com um grande tamanho retido. Procure vazamentos de memória causados por:
- Referências de longa duração a
ActivityouContextque podem vazar o gráfico de composição do Compose hospedado (como oComposeViewe os subelementos combináveis dele). - Vazamento de objetos de estado do Jetpack Compose (
MutableState), detentores de estado ou lambdas que capturamContext. - Esquecer de limpar listeners ou observadores no bloco
onDisposede umDisposableEffect. - Classes internas não estáticas, como um
Runnable, que podem conter uma instânciaActivity. - Caches que armazenar objetos por mais tempo do que o necessário.
Ao encontrar possíveis vazamentos de memória, use as guias Fields e References em Instance Details para acessar a instância ou a linha de código-fonte de interesse.
Acionar vazamentos de memória para testes
Para analisar o uso da memória, você precisa estressar o código do app e tentar forçar vazamentos de memória. Uma forma de provocar vazamentos de memória no app é deixar que ele seja executado por algum tempo antes de inspecionar a heap. Os vazamentos podem chegar ao topo das alocações no heap. No entanto, quanto menor o vazamento, maior o tempo de execução do app necessário para poder vê-lo.
Também é possível usar um dos seguintes métodos para provocar um vazamento de memória:
- Gire o dispositivo do modo retrato para o modo paisagem e vice-versa várias vezes
em diferentes estados de atividade. Girar o dispositivo geralmente pode fazer com que um app
vaze uma
Activity(e, consequentemente, a árvore de interface do Compose hospedada e as árvores de estado associadas) se o app tiver uma referência àActivityou àContextem operações assíncronas ou detentores de estado. - Alternar entre o app e outro app em diferentes estados de atividade. Por exemplo, navegue até a tela inicial e volte para o app.
Exportar e importar uma gravação de heap dump
É possível
exportar e importar um arquivo de heap dump
na guia Past Recordings no criador de perfil. O Android Studio salva a
gravação como um arquivo .hprof.
Como alternativa, para usar um analisador de arquivos .hprof diferente, como o
jhat,
é necessário converter o arquivo .hprof do formato do Android para o formato de arquivo .hprof
do Java SE. Para converter o formato do arquivo, use a ferramenta hprof-conv
fornecida no diretório {android_sdk}/platform-tools/. Execute o comando hprof-conv
com dois argumentos: o nome do arquivo .hprof original e o local para
gravar o arquivo .hprof convertido, incluindo o novo nome do arquivo .hprof. Exemplo:
hprof-conv heap-original.hprof heap-converted.hprof