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 umFragmentManager
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 umFragmentTransaction
.
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êinerActivity
ouContext
. - Classes internas não estáticas, como
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 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
ouView
porque o sistema recria oActivity
. 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