Gerar um heap dump

Capture um despejo de heap para ver quais objetos do app estão usando memória no momento da captura e identifique vazamentos de memória ou um comportamento de alocação de memória que cause oscilações, travamentos e até falhas no app. É especialmente útil fazer despejos de heap após uma sessão de usuário prolongada, quando eles podem mostrar objetos ainda na memória que não deveriam estar lá.

Esta página descreve as ferramentas que o Android Studio oferece para coletar e analisar despejos de heap. Como alternativa, é possível inspecionar a memória do app na linha de comando com dumpsys e também ver eventos de coleta de lixo (GC) no Logcat.

Por que é necessário criar o perfil da memória do app

O Android oferece um ambiente de memória gerenciado: quando o Android determina que o app não está mais usando alguns objetos, o coletor de lixo libera a memória não utilizada de volta para a heap. A forma como o Android encontra memória não utilizada é constantemente aprimorada. No entanto, em todas as versões do Android, o sistema precisa interromper brevemente seu código em algum momento. Geralmente, as interrupções são imperceptíveis. No entanto, se o app alocar memória com mais rapidez do que o sistema consegue coletá-la, o app poderá ficar mais lento 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. Se isso ocorrer, quando o usuário retornar ao aplicativo, o processo do app precisará ser reiniciado completamente.

Para saber mais sobre práticas de programação que podem reduzir o uso de memória do app, leia Gerenciar a memória do app.

Visão geral do heap dump

Para capturar um heap dump, selecione a tarefa Analisar uso de memória (heap dump) (use Profiler: execute "app" como depurável (dados completos)). 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 visualização de despejo de heap no Profiler do Android Studio.

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ê verá memória aqui para alguns objetos alocados em Java porque o Android usa memória nativa para algumas classes de framework, como Bitmap.

  • Shallow Size: quantidade total de memória Java usada por esse tipo de objeto (em bytes).

  • Retained Size: tamanho total da memória que está sendo retida devido a todas as instâncias dessa classe (em bytes).

Use o menu de heap para filtrar determinados heaps:

  • Heap do app (padrão): a heap principal em que o app aloca memória.
  • Image heap: a imagem de inicialização do sistema, que contém as classes pré-carregadas durante a inicialização. As alocações aqui nunca são movidas ou eliminadas.
  • 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:

  • Organizar por classe (padrão): agrupa todas 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 "Turma" para filtrar grupos de turmas:

  • Todas as classes (padrão): mostra todas as classes, incluindo as de bibliotecas e dependências.
  • Mostrar vazamentos de atividade/fragmento: mostra classes que estão causando vazamentos de memória.
  • Mostrar classes do projeto: mostra apenas as classes definidas pelo seu projeto.

Clique no nome de uma classe para abrir o painel Instância. 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 é visível apenas para o Android 7.0 e versões mais recentes.
  • Shallow Size: o tamanho da instância na memória Java.
  • Retained Size: 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 de campo e referência comuns 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 nesta instância.
  • Referências: mostra todas as referências ao objeto destacado na guia Instância.
As visualizações Instâncias, Campos e Referências na janela de ferramentas de despejo de heap.

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 Mostrar vazamentos de atividade/fragmento. O Android Studio mostra classes que ele considera como vazamentos de memória em instâncias de Activity e Fragment no 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 Tamanho retido grande. Procure vazamentos de memória causados por:

  • Referências de longa duração a Activity ou Context que podem vazar o gráfico de composição do Compose hospedado (como o ComposeView e seus subcomponíveis).
  • Vazamento de objetos de estado do Jetpack Compose (MutableState), detentores de estado ou lambdas que capturam Context.
  • Esquecer de limpar listeners ou observadores no bloco onDispose de um DisposableEffect.
  • Classes internas não estáticas, como um Runnable, que podem conter uma instância Activity.
  • Caches que armazenar objetos por mais tempo do que o necessário.

Quando encontrar possíveis vazamentos de memória, use as guias Campos e Referências em Detalhes da instância para acessar a instância ou a linha de código-fonte de interesse.

Acionar vazamentos de memória para teste

Para analisar o uso da memória, estresse o código do app e tente 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 subir para a parte superior das alocações na heap. No entanto, quanto menor o vazamento, maior será 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 da orientação retrato para paisagem e vice-versa várias vezes em diferentes estados de atividade. A rotação do dispositivo pode fazer com que um app vaze um Activity (e, consequentemente, a árvore de interface do Compose hospedada e as árvores de estado associadas) se o app mantiver uma referência ao Activity ou Context em operações assíncronas ou detentores de estado.
  • Alterne entre seu 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 Gravações anteriores do 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 jhat, é preciso converter o arquivo .hprof do formato 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

Outros recursos