Gerência de Memória em Sistemas Linux: Ocorrencias quando a Memória Está Esgotada
Este artigo explora o que acontece em um sistema Linux quando a memória física está esgotada, abordando os mecanismos de gerenciamento de memória e suas implicações de desempenho.
Processo de Alocação de Memória
Quando um aplicativo solicita memória através da função malloc, na verdade está solicitando memória virtual. Nesse momento, nenhuma memória física é alocada imediatamente.
Quando o aplicativo acessa essa memória virtual, o CPU tenta acessá-la e descobre que não há mapeamento com memória física. Isso aciona uma interrupção de página ausente, fazendo com que o processo mude do modo usuário para o modo kernel. O manipulador de interrupção de página ausente do kernel verifica se há memória física disponível.
Se houver memória física livre, ela é alocada e estabelece-se o mapeamento entre memória virtual e memória física. Caso contrário, o kernel inicia o processo de recuperação de memória, que pode ocorrer de duas formas:
- Recuperação de memória em segundo plano (kswapd): Quando a memória física está tensionada, o kernel thread kswapd é acionado para recuperar memória de forma assíncrona, sem bloquear a execução do processo.
- Recuperação de memória direta: Se a recuperação assíncrona não acompanhar a velocidade de solicitação de memória dos processos, inicia-se uma recuperação síncrona que bloqueia a execução do processo.
Se mesmo após a recuperação direta não houver memória física suficiente para a solicitação atual, o kernel recorre a sua última opção: acionar o mecanismo OOM (Out of Memory). O OOM Killer seleciona um processo que consome muita memória e o encerra para liberar recursos. Se a memória ainda for insuficiente, o processo continua sendo selecionado até que haja memória suficiente.
Quais Tipos de Memória Podem ser Recuperados?
Quando a memória do sistema está tensionada, o kernel pode recuperar dois tipos principais de memória:
- Páginas de arquivo: São dados de arquivos cacheados pelo kernel. A maioria pode ser liberada diretamente, pois pode ser relida do disco quando necessário. Páginas modificadas (sujas) devem ser gravadas no disco antes da liberação.
- Páginas anônimas: São alocadas dinamicamente por aplicativos através de mmap. Essas páginas não podem ser liberadas diretamente e são recuperadas através do mecanismo Swap do Linux, que move páginas pouco acessadas para o disco.
A recuperação de ambos os tipos de página segue o algoritmo LRU (Least Recent Used), priorizando páginas menos acessadas. O sistema mantém duas listas duplamente ligadas:
- active_list: Armazena páginas recentemente acessadas.
- inactive_list: Armazena páginas raramente acessadas.
As páginas mais próximas do final das listas são as menos acessadas e são priorizadas para recuperação.
Impacto no Desempenho da Recuperação de Memória
A recuperação de memória pode afetar significativamente o desempenho do sistema:
- Recuperação de páginas de arquivo: Páginas limpas são liberadas diretamente sem impacto, enquanto páginas sujas exigem operações de I/O no disco.
- Recuperação de páginas aônimas: O mecanismo Swap realiza operações de leitura/escrita no disco quando páginas são movidas para e do espaço de swap.
Operações frequentes de recuperação de memória resultam em múltiplas operações de I/O, degradando o desempenho do sistema.
Soluções para Mitigar Impactos de Desempenho
-
Ajuste da tendência de recuperação de páginasO Linux oferece a opção
/proc/sys/vm/swappinesspara ajustar a preferência entre recuperação de páginas de arquivo e anônimas. Um valor entre 0-100, onde valores maiores favorecem o uso de Swap (recuperação de páginas anônimas).# Verificar valor atual de swappiness $ cat /proc/sys/vm/swappinessValores menores (como 0) priorizam a recuperação de páginas de arquivo.
-
Acionar antecipadamente a recuperação assíncronaO kernel define três limiares de memória para determinar quando acionar a recuperação:
- pages_min: Limiar mínimo
- pages_low: Limiar baixo
- pages_high: Limiar alto
Quando a memória livre está entre
pages_lowepages_min, o kswapd inicia recuperação assíncrona. Quando a memória está abaixo depages_min, inicia-se recuperação direta.O limiar baixo pode ser ajustado indiretamente através de
/proc/sys/vm/min_free_kbytes:# Relação entre os limiares pages_min = min_free_kbytes pages_low = pages_min * 5/4 pages_high = pages_min * 3/2Aumentar
min_free_kbytesaciona a recuperação assíncrona mais cedo, evitando recuperação direta, mas reduz a memória disponível para aplicativos. -
Estratégia de recuperação em arquitetura NUMAEm sistemas NUMA (Non-Uniform Memory Access), cada nó tem memória local. O modo de recuperação é controlado por
/proc/sys/vm/zone_reclaim_mode:0 (padrão): Procurar memória livre em outros nós antes de recuperar localmente 1: Recuperar apenas memória local 2: Recuperar memória local, incluindo escrita de páginas sujas 4: Recuperar memória local usando SwapRecomenda-se manter o valor 0 para evitar recuperação prematura quando há memória disponível em outros nós.
Proteção de Processos contra o OOM Killer
Quando a memória está esgotada e a recuperação direta não é suficiente, o OOM Killer seleciona processos para encerrar baseado na função oom_badness():
points = process_pages + oom_score_adj * totalpages / 1000
Onde:
process_pages: Número de páginas físicas usadas pelo processooom_score_adj: Valor de ajuste do OOM (-1000 a 1000)totalpages: Número total de páginas disponíveis no sistema
O valor de oom_score_adj pode ser ajustado para /proc/[pid]/oom_score_adj:
- -1000: Protege o processo contra OOM
- 0: Padrão
- 1000: Máxima probabilidade de ser selecionado
Processos críticos como sshd devem ter oom_score_adj = -1000. Para aplicativos de negócio, é melhor não definir -1000 para permitir que processos com vazamento de memória sejam encerrados.