Daemon de eliminação de pouca memória

O processo daemon do Android Low Memory Killer (lmkd) monitora o estado da memória de um sistema Android em execução e reage à alta pressão da memória encerrando os processos menos essenciais para manter o desempenho do sistema em níveis aceitáveis.

Sobre a pressão da memória

Um sistema Android executando vários processos em paralelo pode encontrar situações em que a memória do sistema se esgota e os processos que exigem mais memória sofrem atrasos perceptíveis. A pressão na memória, um estado em que o sistema está ficando sem memória, exige que o Android libere memória (para aliviar a pressão) limitando ou encerrando processos sem importância, solicitando que os processos liberem recursos não críticos armazenados em cache e assim por diante.

Historicamente, o Android monitorava a pressão da memória do sistema usando um driver de eliminação de pouca memória (LMK) no kernel, um mecanismo rígido que depende de valores codificados. A partir do kernel 4.12, o driver LMK é removido do kernel upstream, e o espaço do usuário lmkd realiza tarefas de monitoramento de memória e encerramento de processos.

Informações de pressão de espera

O Android 10 e versões mais recentes oferecem suporte a um novo modo lmkd que usa monitores de informação de pouca pressão (PSI, na sigla em inglês) do kernel para detecção de pressão da memória. O patchset do PSI no kernel upstream (portado para kernels 4.9 e 4.14) mede o tempo de atraso das tarefas devido à falta de memória. Como esses atrasos afetam diretamente a experiência do usuário, eles representam uma métrica conveniente para determinar a gravidade da pressão da memória. O kernel upstream também inclui monitores de PSI que permitem que processos privilegiados do espaço do usuário (como lmkd) especifiquem limites para esses atrasos e se inscrevam em eventos do kernel quando um limite é violado.

Monitoramento de PSI x indicadores de vmpressure

Como os indicadores vmpressure (gerados pelo kernel para detecção de pressão de memória e usados pelo lmkd) geralmente incluem vários falsos positivos, o lmkd precisa realizar a filtragem para determinar se a memória está sob pressão real. Isso resulta em ativações desnecessárias do lmkd e no uso de recursos computacionais adicionais. O uso do PSI monitora os resultados, o que resulta em uma detecção mais precisa da pressão de memória e minimiza a sobrecarga de filtragem.

Usar monitores do PSI

Para usar monitores do PSI em vez de eventos vmpressure, configure a propriedade ro.lmk.use_psi. O padrão é true, o que torna os monitores de PSI o mecanismo padrão de detecção de pressão da memória para lmkd. Como os monitores de PSI exigem suporte do kernel, ele precisa incluir os patches de backport do PSI e ser compilado com o suporte do PSI ativado (CONFIG_PSI=y).

Desvantagens do driver LMK no kernel

O Android descontinua o driver LMK devido a vários problemas, incluindo:

  • Os dispositivos com pouca RAM precisavam ser ajustados de forma agressiva e, mesmo assim, tinham um desempenho ruim em cargas de trabalho com um grande cache de página ativo com suporte de arquivo. A performance ruim resultou em thrashing e nenhuma morte.
  • O driver do kernel LMK dependia de limites de memória livre, sem escalonamento com base na pressão da memória.
  • Devido à rigidez do design, os parceiros costumavam personalizar o driver para que ele funcionasse nos dispositivos deles.
  • O driver LMK foi conectado à API de redução de slab, que não foi projetada para operações pesadas, como procurar e encerrar alvos, o que deixou o processo vmscan mais lento.

lmkd do espaço do usuário

O lmkd do espaço do usuário implementa a mesma funcionalidade do driver no kernel, mas usa mecanismos de kernel atuais para detectar e estimar a pressão da memória. Esses mecanismos incluem o uso de eventos vmpressure gerados pelo kernel ou monitores de informações de pouca pressão (PSI, na sigla em inglês) para receber notificações sobre níveis de pressão da memória e o uso de recursos de cgroup de memória para limitar os recursos de memória alocados a cada processo com base na importância dele.

Usar o lmkd do espaço do usuário no Android 10

No Android 9 e versões mais recentes, o lmkd do espaço do usuário é ativado se um driver LMK no kernel não for detectado. Como o espaço do usuário lmkd exige suporte do kernel para cgroups de memória, o kernel precisa ser compilado com as seguintes configurações:

CONFIG_ANDROID_LOW_MEMORY_KILLER=n
CONFIG_MEMCG=y
CONFIG_MEMCG_SWAP=y

Estratégias de encerramento

O Userspace lmkd oferece suporte a estratégias de encerramento com base em eventos vmpressure ou monitores PSI, gravidade e outras dicas, como utilização de troca. As estratégias de encerramento são diferentes em dispositivos de pouca memória e de alto desempenho:

  • Em dispositivos com pouca memória, o sistema precisa tolerar uma pressão maior como um modo normal de operação.
  • Em dispositivos de alto desempenho, a pressão de memória deve ser vista como uma situação anormal e corrigida antes que afete o desempenho geral.

É possível configurar a estratégia de encerramento usando a propriedade ro.config.low_ram.

O userspace lmkd também oferece suporte a um modo legado em que toma decisões de encerramento usando as mesmas estratégias do driver LMK no kernel (ou seja, limites de memória livre e cache de arquivos). Para ativar o modo legado, defina a propriedade ro.lmk.use_minfree_levels como true.

Configurar o lmkd

Configure o lmkd para um dispositivo específico usando as seguintes propriedades.

Propriedade Uso Padrão
ro.config.low_ram Especifique se o dispositivo tem pouca RAM ou é de alta performance. false
ro.lmk.use_psi Use monitores do PSI em vez de eventos vmpressure. true
ro.lmk.use_minfree_levels Use limites de memória livre e cache de arquivos para tomar decisões de encerramento de processos (ou seja, corresponda à funcionalidade do driver LMK no kernel). false
ro.lmk.low A pontuação mínima de oom_adj para processos que podem ser encerrados em um nível baixo de vmpressure. 1001
(desativado)
ro.lmk.medium A pontuação mínima de oom_adj para processos qualificados para serem encerrados no nível médio de vmpressure. 800
(serviços armazenados em cache ou não essenciais)
ro.lmk.critical A pontuação mínima de oom_adj para processos qualificados para serem encerrados no nível crítico vmpressure. 0
(qualquer processo)
ro.lmk.critical_upgrade Ative o upgrade para o nível crítico. false
ro.lmk.upgrade_pressure O mem_pressure máximo em que o nível é atualizado porque o sistema está trocando demais. 100
(desativado)
ro.lmk.downgrade_pressure O mem_pressure mínimo em que um evento vmpressure é ignorado porque ainda há memória livre suficiente. 100
(desativado)
ro.lmk.kill_heaviest_task Encerrar a tarefa mais pesada qualificada (melhor decisão) em vez de qualquer tarefa qualificada (decisão rápida). false
ro.lmk.kill_timeout_ms Duração em milissegundos após uma interrupção quando nenhuma outra interrupção será feita. 0
(desativado)
ro.lmk.debug Ative os registros de depuração do lmkd. false

Exemplo de configuração do dispositivo:

PRODUCT_PROPERTY_OVERRIDES += \
    ro.lmk.low=1001 \
    ro.lmk.medium=800 \
    ro.lmk.critical=0 \
    ro.lmk.critical_upgrade=false \
    ro.lmk.upgrade_pressure=100 \
    ro.lmk.downgrade_pressure=100 \
    ro.lmk.kill_heaviest_task=true

lmkd do espaço do usuário no Android 11

O Android 11 melhora o lmkd ao introduzir uma nova estratégia de eliminação. A estratégia de encerramento usa um mecanismo de PSI para detecção de pressão da memória introduzido no Android 10. lmkd no Android 11 considera os níveis de uso de recursos de memória e o thrashing para evitar a falta de memória e a degradação do desempenho. Essa estratégia substitui as anteriores e pode ser usada em dispositivos de alto desempenho e com pouca memória RAM (Android Go).

Requisitos do kernel

Para dispositivos Android 11, o lmkd exige os seguintes recursos do kernel:

  • Inclua patches de PSI e ative a PSI (backports disponíveis nos kernels comuns do Android 4.9, 4.14 e 4.19).
  • Inclua patches de suporte a PIDFD (backports disponíveis nos kernels comuns do Android 4.9, 4.14 e 4.19).
  • Para dispositivos com pouca memória RAM, inclua cgroups de memória.

O kernel precisa ser compilado com as seguintes configurações:

CONFIG_PSI=y

Configurar o lmkd no Android 11

A estratégia de eliminação de memória no Android 11 é compatível com os botões de ajuste e os padrões listados abaixo. Esses recursos funcionam em dispositivos de alto desempenho e com pouca memória RAM.

Propriedade Uso Padrão
Alto desempenho Pouca RAM
ro.lmk.psi_partial_stall_ms O limite parcial de espera de PSI, em milissegundos, para acionar a notificação de pouca memória. Se o dispositivo receber notificações de pressão na memória muito tarde, diminua esse valor para acionar notificações mais cedo. Se as notificações de pressão da memória forem acionadas sem necessidade, aumente esse valor para tornar o dispositivo menos sensível a ruídos. 70 200
ro.lmk.psi_complete_stall_ms O limite completo de PSI em milissegundos para acionar notificações críticas de memória. Se o dispositivo receber notificações de pressão crítica de memória muito tarde, diminua esse valor para acionar notificações mais cedo. Se as notificações de pressão crítica da memória forem acionadas desnecessariamente, aumente esse valor para tornar o dispositivo menos sensível a ruídos. 700
ro.lmk.thrashing_limit O valor máximo de refaltas do conjunto de trabalho como uma porcentagem do tamanho total do pagecache com suporte a arquivos. Refaltas do conjunto de trabalho acima desse valor significam que o sistema está sendo considerado como thrashing do pagecache. Se o desempenho do dispositivo for afetado durante a pressão na memória, diminua o valor para limitar a thrashing. Se o desempenho do dispositivo for encerrado desnecessariamente por motivos de thrashing, aumente o valor para permitir mais thrashing. 100 30
ro.lmk.thrashing_limit_decay O decaimento do limite de thrashing expresso como uma porcentagem do limite original usado para diminuir o limite quando o sistema não se recupera, mesmo após uma interrupção. Se o thrashing contínuo produzir encerramentos desnecessários, diminua o valor. Se a resposta à thrashing contínuo após uma interrupção for muito lenta, aumente o valor. 10 50
ro.lmk.swap_util_max A quantidade máxima de memória trocada como uma porcentagem da memória total trocável. Quando a memória trocada cresce além desse limite, significa que o sistema trocou a maior parte da memória trocável e ainda está sob pressão. Isso pode acontecer quando alocações não trocáveis geram pressão de memória que não pode ser aliviada pela troca, porque a maior parte da memória trocável já foi trocada. O valor padrão é 100, o que efetivamente desativa essa verificação. Se o desempenho do dispositivo for afetado durante a pressão na memória enquanto a utilização da troca estiver alta e o nível de troca livre não estiver caindo para ro.lmk.swap_free_low_percentage, diminua o valor para limitar a utilização da troca. 100 100

Os seguintes knobs de ajuste antigos também funcionam com a nova estratégia de eliminação.

Propriedade Uso Padrão
Alto desempenho Pouca RAM
ro.lmk.swap_free_low_percentage O nível de troca livre como uma porcentagem do espaço de troca total. O `lmkd` usa esse valor como um limite para considerar que o sistema está com pouco espaço de troca. Se o `lmkd` encerrar enquanto houver muito espaço na troca, diminua a porcentagem. Se os encerramentos do `lmkd` acontecerem muito tarde, permitindo que os encerramentos por falta de memória ocorram, aumente a porcentagem. 20 10
ro.lmk.debug Isso ativa os registros de depuração do `lmkd`. Ative a depuração durante o ajuste. false