Entender e resolver problemas de memória do Android

A memória é um recurso crítico e finito em dispositivos Android. Como desenvolvedor de plataforma Android ou OEM, entender como a memória funciona em todos os níveis, do ambiente de execução Java ao kernel do Linux, é essencial para criar um sistema estável e com bom desempenho.

Este guia oferece uma visão geral abrangente da arquitetura de memória do Android, das ferramentas disponíveis para análise e exercícios práticos para ajudar você a identificar e resolver problemas relacionados à memória.

Objetivos

Depois de concluir este guia, você poderá:

  • Explicar os conceitos fundamentais da memória do Android, incluindo o modelo de processo do Zygote e arquivos mapeados na memória.
  • Diferenciar o tamanho do conjunto residente (RSS), o tamanho do conjunto proporcional (PSS) e o tamanho do conjunto exclusivo (USS).
  • Usar ferramentas de linha de comando padrão, como dumpsys meminfo e showmap, para avaliar rapidamente o uso da memória.
  • Capturar e analisar despejos de heap Java usando o AHAT para encontrar vazamentos e alocações excessivas.
  • Usar o Perfetto e o heapprofd para criar perfis de memória nativa e Java em todo o sistema.
  • Entender indicadores de pressão de memória em todo o sistema, como as informações de pressão de estol (PSI, na sigla em inglês), e monitorar a atividade do Low Memory Killer (LMK).
  • Observar a atividade de recuperação no nível do kernel, incluindo a troca de ZRAM e a remoção do cache de página.

Estrutura do guia

Este guia está organizado nas seções a seguir, projetadas para serem lidas em sequência:

  1. Conceitos fundamentais: os princípios técnicos básicos da memória do Android.
  2. Ferramentas de avaliação rápida: como usar meminfo, showmap, e procstats para triagem rápida.
  3. Análise da memória Java: análises detalhadas do heap Java com o AHAT.
  4. Bitmaps e memória: como as imagens afetam a RAM e como usar ferramentas para criar perfis delas.
  5. Análise da memória nativa: como criar perfis de memória C/C++ com o Perfetto e o heapprofd.
  6. WebView e memória: como entender a arquitetura de vários processos e o consumo de memória das WebViews.
  7. O código do app é memória: como entender o carregamento de classes e o aumento do dex afetam a RAM.
  8. Threads e memória: como analisar o custo das pilhas de threads nativas.
  9. Localidade e desempenho da memória: como entender como os padrões de acesso a dados afetam o desempenho da CPU.
  10. Vinculações de serviço e estados de processo: como entender como as dependências entre processos afetam as pontuações de OOM.
  11. Solução de problemas em todo o sistema: monitoramento de PSI, LMK, troca de ZRAM e remoção do cache de página.
  12. Recuperação de memória: remoção e troca: como entender o memcg, a cobrança e a recuperação proativa com memory.reclaim.
  13. Interação kswapd e lmkd: como entender como o kswapd e o lmkd funcionam juntos sob pressão.

Pré-requisitos e ambiente

Este guia apresenta fluxos de trabalho de referência, dados de benchmark e estudos de caso que demonstram como diagnosticar e resolver problemas de memória do Android.

  • Ferramentas de análise: as técnicas neste guia usam principalmente ferramentas de desempenho padrão do Android, incluindo Perfetto, dumpsys meminfo, showmap, e AHAT.
  • Privilégios de raiz: alguns fluxos de trabalho de diagnóstico no nível do sistema (como inspecionar a pressão de memória do kernel ou contadores PMU de hardware) exigem privilégios de raiz elevados (adb root) em um dispositivo userdebug ou build de emulador.

Comece aqui: Conceitos fundamentais