Gerar um heap dump

Capture um despejo de heap para saber quais objetos do app estão usando memória no momento da captura e identificar vazamentos de memória ou o comportamento de alocação de memória que leva a oscilações, travamentos e até falhas no app. É especialmente útil fazer despejos de heap após uma sessão de usuário prolongada, quando ele pode mostrar objetos que ainda estão na memória e que não deveriam estar mais 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 é sempre aprimorada. No entanto, em todas as versões do Android, o sistema precisa pausar brevemente o código. Na maior parte das vezes, 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. Quando o usuário retornar ao app, o processo dele precisa 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 Analyze Memory Usage (Heap Dump) (use Profiler: run 'app' as debuggable (complete data)) para capturar um heap dump. Durante o despejo de heap, a quantidade de memória do Java pode aumentar temporariamente. Isso é normal porque o despejo de heap ocorre no mesmo processo do app e precisa de memória para coletar os dados. Depois de capturar o despejo de heap, você verá o seguinte:

A lista de classes 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 encontrar 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 pilhas para filtrar determinadas pilhas:

  • App heap (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: uma 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 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 de classes para filtrar grupos de classes:

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

Clique no nome de uma classe para abrir o painel Instance. Cada instância listada inclui:

  • 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 de 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.

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 as classes que ele considera indicar vazamentos de memória para Activity e Fragment instâncias no app. Os tipos de dados mostrados pelo filtro incluem:

  • Instâncias de Activity que foram destruídas, mas ainda estão sendo referenciadas.
  • Instâncias de Fragment que não têm um FragmentManager válido, mas ainda estão sendo referenciadas.

O filtro pode gerar falsos positivos nas seguintes situações:

  • Um Fragment foi criado, mas ainda não foi usado.
  • Um Fragment está sendo armazenado em cache, mas não como parte de um FragmentTransaction.

Para procurar vazamentos de memória de forma mais manual, navegue pelas listas de classes e instâncias para encontrar objetos com tamanho retido grande. Procure vazamentos de memória causados por um dos seguintes motivos:

  • Referências prolongadas a Activity, Context, View, Drawable e outros objetos que podem manter uma referência ao contêiner Activity ou Context.
  • Classes internas não estáticas, como Runnable, que podem conter uma instância Activity.
  • 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 pular para a instância ou linha de código-fonte de interesse.

Acionar vazamentos de memória para testes

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 pilha. No entanto, quanto menor o vazamento, maior o tempo necessário de execução do app 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. Muitas vezes, a rotação do dispositivo pode fazer com que o app vaze um objeto Activity, Context ou View porque o sistema recria o Activity. Se o app mantiver uma referência a um desses objetos em outro lugar, o sistema não poderá eliminá-lo por meio da coleta de lixo.
  • 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 despejo de heap na guia Past Recordings do profiler. O Android Studio salva a gravação como um arquivo .hprof.

Como alternativa, para usar um analisador de arquivos .hprof diferente, como jhat, é necessário converter o arquivo .hprof do formato Android para o formato de arquivo .hprof do Java SE. Para converter o formato de arquivo, use a ferramenta hprof-conv fornecida no diretório {android_sdk}/platform-tools/. Execute o comando hprof-conv com dois argumentos: o nome de arquivo .hprof original e o local para gravar o arquivo .hprof convertido, incluindo o novo nome de arquivo .hprof. Por exemplo:

hprof-conv heap-original.hprof heap-converted.hprof