O Android 17 e versões mais recentes oferecem suporte ao limitador de memória, que é um serviço do sistema que monitora e limita o uso da memória de processos de aplicativos usando o cgroup v2 do Linux. O limitador de memória impede que apps individuais consumam memória excessiva do sistema, o que reduz a pressão da memória em todo o sistema e evita o encerramento agressivo por falta de memória (OOM) de processos críticos.
Mecanismo
O Memory Limiter se integra ao serviço Activity Manager (AMS) para rastrear eventos de ciclo de vida do processo e mudanças de estado. O Memory Limiter aplica limites de memória usando o sistema de arquivos cgroup v2 do kernel do Linux.
Para usar o Memory Limiter, o kernel do dispositivo precisa oferecer suporte a cgroup v2 e ao controlador
memory. O serviço depende especificamente dos seguintes atributos:
memory.high- Um limite flexível. Quando excedido, o processo é limitado e o kernel tenta recuperar a memória dele.
memory.swap.max- Limita a quantidade de espaço de troca que o processo pode usar.
Impacto nos apps
Os apps que não excedem os limites de memória não são afetados pelo Memory Limiter.
Quando um app ultrapassa o limite de memory.high, o kernel desaloca a memória
baseada em arquivo do app e troca a memória anônima para manter o app dentro do
limite. Como resultado do despejo e da troca, o app pode ficar mais lento.
No extremo, se o app continuar alocando memória anônima e o dispositivo ficar sem espaço de troca, o app poderá não alocar memória e, como resultado, provavelmente vai falhar.
Monitoramento de processos
Por padrão, o Memory Limiter monitora processos de apps (UID >= 10000). Os processos do sistema geralmente são isentos para ajudar a verificar a estabilidade do sistema principal.
O Memory Limiter atribui limites de memória com base no estado do processo:
Processos visíveis são perceptíveis para o usuário, como atividades em primeiro plano, serviços em primeiro plano ou outros estados perceptíveis de instabilidade.
Os processos não visíveis são executados em segundo plano e não interagem com o usuário nem ficam visíveis para ele.
A tabela a seguir mapeia estados de processo específicos para limites de memória:
| Estado do processo | Limite de memória |
|---|---|
PERSISTENT | Irrestrito |
PERSISTENT_UI | Irrestrito |
TOP | Visível |
BOUND_TOP | Visível |
FOREGROUND_SERVICE | Não visível |
BOUND_FOREGROUND_SERVICE | Não visível |
IMPORTANT_FOREGROUND | Visível |
IMPORTANT_BACKGROUND | Não visível |
TRANSIENT_BACKGROUND | Não visível |
BACKUP | Não visível |
SERVICE | Não visível |
RECEIVER | Não visível |
TOP_SLEEPING | Visível |
HEAVY_WEIGHT | Não visível |
HOME | Não visível |
LAST_ACTIVITY | Não visível |
CACHED_ACTIVITY | Armazenado em cache |
CACHED_ACTIVITY_CLIENT | Armazenado em cache |
CACHED_RECENT | Armazenado em cache |
CACHED_EMPTY | Armazenado em cache |
No estado em cache, os processos são congelados e depois recuperados ao máximo.
Quando um processo excede o limite de memory.high atribuído, o Memory Limiter
detecta o evento e pode acionar ações de depuração, como capturar um perfil
de memória ou registrar uma anomalia em statsd.
Configuração
Configure o limitador de memória usando um arquivo XML localizado na partição vendor. A configuração permite ajustar os limites absolutos de memória com base nas restrições específicas do dispositivo.
Caminho do arquivo:
/vendor/etc/memory-limiter-config.xmlConfiguração padrão:se o arquivo de configuração não for encontrado ou se ele estiver ilegível ou inválido, o limitador de memória será desativado.
Formato XML
O arquivo de configuração segue o esquema definido em
memory-limiter-config.xsd. O arquivo permite definir vários conjuntos de limites, e o serviço escolhe a melhor correspondência com base na RAM disponível do dispositivo. Todos os valores de memória são definidos em unidades de mebibytes (MiB).
<MemoryLimiterConfig>
<version>1</version>
<configList>
<limitSet>
<!-- Limits for a phone with at least 14G of ram: 8G/4G/4G/4G -->
<minimumRequiredMemTotal>14336</minimumRequiredMemTotal>
<memVisible>8192</memVisible>
<memNotVisible>4096</memNotVisible>
<swapVisible>4096</swapVisible>
<swapNotVisible>4096</swapNotVisible>
</limitSet>
</configList>
</MemoryLimiterConfig>
version- Um número inteiro positivo que identifica a versão da configuração. Precisa ser 1.
minimumRequiredMemTotal- A memória mínima disponível do sistema necessária para que esse limite seja válido.
memVisible- O limite de memória (
memory.high) permitido para processos visíveis. memNotVisible- O limite de memória (
memory.high) permitido para processos não visíveis. swapVisible- O limite de troca (
memory.swap.max) permitido para processos visíveis. swapNotVisible- O limite de troca (
memory.swap.max) permitido para processos não visíveis.
Modificar configuração
Para mudar os limites em todo o sistema, siga estas etapas:
- Modificar
/vendor/etc/memory-limiter-config.xml. - Reinicie o dispositivo ou o
system_serverpara que as mudanças entrem em vigor.
Comandos do shell
O comando am memory-limiter permite que você e os desenvolvedores interajam com o
serviço no tempo de execução para desenvolvimento e teste:
am memory-limiter <SUB-COMMAND>status
O subcomando status informa o status operacional do Memory Limiter:
adb shell am memory-limiter statusExemplo de saída:
Memory limiter
enabled monitoring=true ignored=none
visibleMem=1948MB visibleSwap=974MB
notVisibleMem=974MB notVisibleSwap=487MB
started=36 watched=36 watch-failed=0
events=0 processes=36 process-hwm=36
Os principais campos na saída incluem:
monitoring- Indica se o limitador está monitorando ativamente os processos.
visibleMemenotVisibleMem- Indique os limites absolutos de memória calculados para cada estado.
events- O número de vezes que um processo excedeu o limite.
processes- O número de processos monitorados.
ignorar
O subcomando ignore exclui temporariamente um UID ou todos os processos de serem
limitados. Essa ação é útil para testes de desempenho ou quando você permite que um
app específico exceda os limites.
adb shell am memory-limiter ignore 10087 // Ignore a specific UIDadb shell am memory-limiter ignore all // Ignore all processes (effectively disables limiting)adb shell am memory-limiter ignore none // Resume normal operation
manual
O subcomando manual substitui os limites calculados de um processo específico (por ID do processo ou PID) com um valor absoluto personalizado em megabytes (MB):
adb shell am memory-limiter manual 1234 1024 // Set a 1024 MB limit for PID 1234adb shell am memory-limiter manual 1234 none // Remove the manual override for PID 1234
As substituições manuais se aplicam apenas ao ciclo de vida do processo. Se o processo for reiniciado, ele voltará aos limites padrão com base no estado.