Gravar alocações Java/Kotlin

A gravação de alocações em Java/Kotlin ajuda a identificar padrões de memória indesejáveis que podem estar causando problemas de desempenho. O criador de perfil pode mostrar as seguintes informações sobre as alocações de objeto:

  • Que tipos de objetos foram alocados e quanto espaço eles usam.
  • O rastreamento de pilha de cada alocação, incluindo a linha de execução onde a alocação foi efetuada.
  • Quando os objetos foram desalocados.

Grave alocações de memória durante interações normais e extremas do usuário para identificar exatamente onde o código aloca um número excessivo de objetos em um curto período ou aloca objetos que vazam. Saiba por que é necessário criar o perfil da memória do app.

Como gravar alocações Java/Kotlin

Para gravar alocações Java/Kotlin, selecione a tarefa Track Memory Consumption (Java/Kotlin Allocations) na guia Home do profiler. É necessário ter um app depurável (use Profiler: run 'app' as debuggable (complete data)) para gravar alocações em Java/Kotlin.

Por padrão, o Android Studio captura todas as alocações de objetos na memória. Se você tiver um app que aloca muitos objetos, poderá observar lentidões visíveis durante a criação de perfil. Para melhorar a performance durante a criação de perfil, acesse o menu suspenso Rastreamento de alocação e selecione Amostrado em vez de Completo. Ao criar amostras, o criador de perfil coleta alocações de objetos na memória em intervalos regulares.

Para forçar um evento de coleta de lixo durante a gravação, clique no ícone de lixeira .

Visão geral das alocações de Java/Kotlin

Depois de interromper a gravação, você verá o seguinte:

  • A linha do tempo de eventos mostra estados de atividade, eventos de entrada do usuário e eventos de rotação de tela.
  • A linha do tempo de uso da memória mostra as seguintes informações. Selecione uma parte da linha do tempo para filtrar um determinado período.
    • Um gráfico empilhado mostrando quanta memória está sendo usada em cada categoria de memória, como indicado pelo eixo y à esquerda e pela legenda de cores na parte de cima.
    • Uma linha tracejada indica o número de objetos alocados, conforme indicado pelo eixo y à direita.
    • Um ícone para cada evento de coleta de lixo.
  • A guia Tabela mostra uma lista de turmas. A Contagem total é o número de alocações no final do período selecionado (Alocações menos Desalocações). Portanto, faz sentido depurar primeiro as classes com os maiores valores de Contagem total. Se você quiser resolver problemas de classes com base nas alocações de pico durante o período selecionado, priorize por Alocações. Da mesma forma, o Remaining Size é o Allocations Size menos o Deallocations Size em bytes.
  • Ao clicar em uma classe na lista Tabela, o painel Instância é aberto com uma lista de objetos associados, incluindo quando foram alocados e desalocados, além do tamanho superficial.
  • A guia Visualização mostra uma visão agregada de todos os objetos na pilha de chamadas durante o período selecionado. Ela mostra essencialmente quanta memória total a callstack com as instâncias mostradas ocupa. A primeira linha mostra o nome da linha de execução. Por padrão, os objetos são empilhados da esquerda para a direita com base no tamanho da alocação. Use o menu suspenso para mudar a ordem.

  • Use o menu suspenso de heap para filtrar determinados heaps. Além dos filtros disponíveis ao capturar um despejo de heap, é possível filtrar classes na heap da JNI, que mostra onde as referências da Java Native Interface (JNI) são alocadas e liberadas.

  • Use o menu suspenso de organização para escolher como organizar as alocações. Além dos arranjos disponíveis ao capturar um despejo de heap, você pode organizar por callstack.

Como a memória é contada

Os números exibidos na parte de cima são baseados em todas as páginas de memória privada confirmadas pelo app, de acordo com o sistema Android. Essa contagem não inclui páginas compartilhadas com o sistema ou outros apps. As categorias na contagem de memória são as seguintes:

  • Java: memória de objetos alocados em código Java ou Kotlin.
  • Native: memória de objetos alocados em código C ou C++.

    Mesmo que você não use C++ no app, pode ver alguma memória nativa usada aqui, porque o framework do Android usa memória nativa para processar várias tarefas em seu nome, como o processamento de recursos de imagem e outros gráficos— mesmo que o código tenha sido escrito em Java ou Kotlin.

  • Memória gráfica: usada para filas do buffer de gráficos para exibir pixels na tela, incluindo superfícies GL, texturas GL e muito mais. Essa é uma memória compartilhada com a CPU e não a memória dedicada da GPU.

  • Stack: memória usada pelas pilhas nativa e Java no app. Geralmente, isso está relacionado a quantas linhas de execução seu app está executando.

  • Code: memória usada pelo app para código e recursos, como bytecode DEX, código DEX otimizado ou compilado, .bibliotecas so e fontes.

  • Outros: memória usada pelo app que o sistema não sabe como categorizar.

  • Allocated: o número de objetos Java/Kotlin alocados pelo app. Isso não inclui objetos alocados em C ou C++.

Inspecionar o registro de alocação

Para inspecionar o registro de alocação, siga estas etapas:

  1. Procure na lista de classes na guia Tabela objetos com valores de Alocações ou Contagem total anormalmente grandes (dependendo do que você está otimizando) e que podem ter vazamentos.
  2. No painel Instance View, clique em uma instância. Dependendo do que for aplicável a essa instância, a guia Campos ou Rastreamento de pilha de chamadas de alocação será aberta. Use as informações nas guias Campos ou Stack de chamadas de alocação para determinar se as instâncias são realmente necessárias ou duplicações desnecessárias.

Clique com o botão direito do mouse em qualquer entrada da lista para acessar o código-fonte relevante.

Ver referências globais de JNI

A Java Native Interface (JNI) é uma estrutura que permite que o código Java e o código nativo se chamem. As referências de JNI são gerenciadas manualmente pelo código nativo, portanto, é possível que ocorram problemas, incluindo os seguintes:

  • Objetos Java usados pelo código nativo são mantidos ativos por muito tempo.
  • Alguns objetos na heap Java podem ficar inacessíveis se uma referência de JNI for descartada sem primeiro ser explicitamente excluída.
  • O limite de referências globais de JNI foi esgotado.

Para solucionar esses problemas, selecione Ver heap JNI no profiler para procurar todas as referências JNI globais e filtrá-las por tipos de Java e pilhas de chamadas nativas. Clique com o botão direito do mouse em um campo de instância na guia Campos e selecione Ir para instância para ver a pilha de chamadas de alocação relevante.

A guia Allocation Call Stack mostra onde as referências de JNI são alocadas e liberadas no código.

Para saber mais sobre JNI, consulte as dicas de JNI.