O oom-killer geralmente tem má reputação entre os usuários do Linux. Isso pode ser parte do motivo pelo qual o Linux o invoca apenas quando não tem outra escolha. Ele trocará o ambiente de área de trabalho, eliminará todo o cache da página e esvaziará todos os buffers antes de encerrar um processo. Pelo menos é o que acho que fará. Ainda preciso ser paciente o suficiente para esperar por isso, sentado diante de um sistema que não responde.
Isso fez com que eu e outras pessoas nos questionássemos se o oom-killer poderia ser configurado para intervir antes: reddit r/linux, superuser.com, unix.stackexchange.com.
Acontece que não, não pode. Pelo menos usando o oom-killer no kernel. No espaço do usuário, entretanto, podemos fazer o que quisermos.
earlyoom quer ser simples e sólido. Está escrito em C puro, sem dependências. Um extenso conjunto de testes (testes de unidade e integração) é escrito em Go.
O earlyoom verifica a quantidade de memória disponível e a troca livre até 10 vezes por segundo (com menos frequência se houver muita memória livre). Por padrão, se ambos estiverem abaixo de 10%, o maior processo será encerrado ( oom_score
mais alto). O valor percentual é configurável por meio de argumentos de linha de comando.
Na saída free -m
abaixo, a memória disponível é 2170 MiB e a troca livre é 231 MiB.
total used free shared buff/cache available
Mem: 7842 4523 137 841 3182 2170
Swap: 1023 792 231
Por que a memória “disponível” é verificada em vez da memória “livre”? Em um sistema Linux saudável, a memória “livre” deve estar próxima de zero, porque o Linux usa toda a memória física disponível para armazenar em cache o acesso ao disco. Esses caches podem ser eliminados sempre que a memória for necessária para outra coisa.
A memória "disponível" é responsável por isso. Ele resume toda a memória não utilizada ou que pode ser liberada imediatamente.
Observe que você precisa de uma versão recente free
e do kernel Linux 3.14+ para ver a coluna "disponível". Se você tiver um kernel recente, mas uma versão antiga de free
, poderá obter o valor em grep MemAvailable /proc/meminfo
.
Quando a memória disponível e a troca livre caírem abaixo de 10% da memória total disponível para processos do espaço do usuário (= total compartilhado), ele enviará o sinal SIGTERM
para o processo que usa mais memória na opinião do kernel ( /proc/*/oom_score
).
earlyoom não usa echo f > /proc/sysrq-trigger
porque:
Em algumas versões do kernel (testadas na v4.0.5), acionar o kernel oom killer manualmente não funciona. Ou seja, ele pode liberar apenas alguma memória gráfica (que será alocada imediatamente novamente) e não matar nenhum processo. Aqui você pode ver como fica na minha máquina (gráficos integrados Intel).
Este problema foi corrigido no Linux v5.17 (commit f530243a).
Como o kernel do Linux faria, o earlyoom encontra sua vítima lendo /proc/*/oom_score
.
Cerca de 2 MiB
( VmRSS
), embora apenas 220 kiB
seja memória privada ( RssAnon
). O resto é a biblioteca libc ( RssFile
) que é compartilhada com outros processos. Toda a memória é bloqueada usando mlockall()
para garantir que o earlyoom não fique lento em situações de pouca memória.
Compilar você mesmo é fácil:
git clone https://github.com/rfjakob/earlyoom.git
cd earlyoom
make
Opcional: Execute os autotestes integrados:
make test
Inicie o earlyoom automaticamente registrando-o como um serviço:
sudo make install # systemd
sudo make install-initscript # non-systemd
Observe que para sistemas com SELinux desabilitado (Ubuntu 19.04, Debian 9 ...) os avisos chcon que relatam falha na definição do contexto podem ser ignorados com segurança.
Para Debian 10+ e Ubuntu 18.04+, existe um pacote Debian:
sudo apt install earlyoom
Para Fedora e RHEL 8 com EPEL, existe um pacote Fedora:
sudo dnf install earlyoom
sudo systemctl enable --now earlyoom
Para Arch Linux, existe um pacote Arch Linux:
sudo pacman -S earlyoom
sudo systemctl enable --now earlyoom
Disponibilidade em outras distribuições: consulte a página de repologia.
Basta iniciar o executável que você acabou de compilar:
./earlyoom
Ele informará quanta memória e swap você tem, qual é o mínimo, quanta memória está disponível e quanto de swap está livre.
./earlyoom
eearlyoom v1.8
mem total: 23890 MiB, user mem total: 21701 MiB, swap total: 8191 MiB
sending SIGTERM when mem avail <= 10.00% and swap free <= 10.00%,
SIGKILL when mem avail <= 5.00% and swap free <= 5.00%
mem avail: 20012 of 21701 MiB (92.22%), swap free: 5251 of 8191 MiB (64.11%)
mem avail: 20031 of 21721 MiB (92.22%), swap free: 5251 of 8191 MiB (64.11%)
mem avail: 20033 of 21723 MiB (92.22%), swap free: 5251 of 8191 MiB (64.11%)
[...]
Se os valores caírem abaixo do mínimo, os processos serão eliminados até que estejam acima do mínimo novamente. Cada ação é registrada em stderr. Se você estiver executando o earlyoom como um serviço systemd, poderá visualizar as últimas 10 linhas usando
systemctl status earlyoom
Para ver earlyoom
em ação, crie/simule um vazamento de memória e deixe earlyoom
fazer o que faz:
tail /dev/zero
Se precisar de mais ações após um processo ser encerrado pelo earlyoom
(como o envio de e-mails), você pode analisar os logs:
sudo journalctl -u earlyoom | grep sending
A saída de exemplo para o comando de teste acima ( tail /dev/zero
) será semelhante a:
Feb 20 10:59:34 debian earlyoom[10231]: sending SIGTERM to process 7378 uid 1000 "tail": oom_score 156, VmRSS 4962 MiB
Para versões mais antigas do
earlyoom
, use:sudo journalctl -u earlyoom | grep -iE "(sending|killing)"
Desde a versão 1.6, o earlyoom pode enviar notificações sobre processos eliminados através do d-bus do sistema. Passe -n
para habilitá-los.
Para realmente ver as notificações em sua sessão GUI, você precisa ter o systembus-notify em execução como seu usuário.
Além disso, o earlyoom pode executar um script para cada processo eliminado, fornecendo informações sobre o processo por meio das variáveis de ambiente EARLYOOM_PID
, EARLYOOM_UID
e EARLYOOM_NAME
. Passe -N /path/to/script
para ativar.
Aviso: No caso do modo dryrun, o script será executado em rápida sucessão, certifique-se de ter algum tipo de limite de taxa implementado.
O sinalizador de linha de comando --prefer
especifica processos que preferem matar; da mesma forma, --avoid
especifica processos para evitar mortes. Consulte https://github.com/rfjakob/earlyoom/blob/master/MANPAGE.md#--prefer-regex para obter detalhes.
Se você estiver executando o earlyoom como um serviço do sistema (através do systemd ou init.d), poderá ajustar sua configuração por meio do arquivo fornecido em /etc/default/earlyoom
. O arquivo já contém alguns exemplos nos comentários, que você pode usar para construir seu próprio conjunto de configurações com base nas opções de linha de comando suportadas, por exemplo:
EARLYOOM_ARGS="-m 5 -r 60 --avoid '(^|/)(init|Xorg|ssh)$' --prefer '(^|/)(java|chromium)$'"
Após ajustar o arquivo, basta reiniciar o serviço para aplicar as alterações. Por exemplo, para systemd:
systemctl restart earlyoom
Observe que este arquivo de configuração não tem efeito em instâncias do earlyoom fora de systemd/init.d.
earlyoom v1.8
Usage: ./earlyoom [OPTION]...
-m PERCENT[,KILL_PERCENT] set available memory minimum to PERCENT of total
(default 10 %).
earlyoom sends SIGTERM once below PERCENT, then
SIGKILL once below KILL_PERCENT (default PERCENT/2).
-s PERCENT[,KILL_PERCENT] set free swap minimum to PERCENT of total (default
10 %).
Note: both memory and swap must be below minimum for
earlyoom to act.
-M SIZE[,KILL_SIZE] set available memory minimum to SIZE KiB
-S SIZE[,KILL_SIZE] set free swap minimum to SIZE KiB
-n enable d-bus notifications
-N /PATH/TO/SCRIPT call script after oom kill
-g kill all processes within a process group
-d, --debug enable debugging messages
-v print version information and exit
-r INTERVAL memory report interval in seconds (default 1), set
to 0 to disable completely
-p set niceness of earlyoom to -20 and oom_score_adj to
-100
--ignore-root-user do not kill processes owned by root
--sort-by-rss find process with the largest rss (default oom_score)
--prefer REGEX prefer to kill processes matching REGEX
--avoid REGEX avoid killing processes matching REGEX
--ignore REGEX ignore processes matching REGEX
--dryrun dry run (do not kill any processes)
--syslog use syslog instead of std streams
-h, --help this help text
Consulte a página de manual para obter detalhes.
Relatórios de bugs e solicitações pull são bem-vindos via github. Em particular, tenho o prazer de aceitar
v1.8.2, 07/05/2024
earlyoom.service
process_mrelease
às syscalls permitidas (commit)IPAddressDeny
(confirmação)-p
(confirmar)v1.8.1, 17/04/2024
v1.8, 15/04/2024
user mem total
/ meminfo_t.UserMemTotal
e calcule MemAvailablePercent com base nele (commit, mais informações na página de manual)process_mrelease
(#266)NO_COLOR
(https://no-color.org/)--sort-by-rss
, obrigado @RanHuang! Isso selecionará um processo para eliminar a conta. para o maior RSS em vez do maior oom_score.v1.7, 05/03/2022
-N
para executar um script sempre que um processo for eliminado (commit, seção da página de manual)-g
para eliminar todo o grupo de processos (#247)-i
(ignorado para compatibilidade), ele não funciona corretamente nos kernels Linux 5.9+ (#234)v1.6.2, 14/10/2020
1.6.1, 07/07/2020
1.6, 11/04/2020
notify-send
por dbus-send
/ systembus-notify (#183)-n
/ -N
agora habilita a nova lógica/proc
montado com hidepid normalmente (edição #184)v1.5, 22/03/2020
-p
: defina oom_score_adj como -100
em vez de -1000
(#170)-M
e -m
e -S
e -s
. Será utilizado o valor menor (convertido em porcentagens).earlyoom.default
para 1 hora em vez de 1 minuto (#177)v1.4, 01/03/2020
uid
dos processos eliminados, além do pid e do nomemake test
)cppcheck
quando disponívelmake bench
)earlyoom.service
v1.3.1, 27/02/2020
v1.3, 26/05/2019
v1.2, 28/10/2018
-k
, agora ignorado para compatibilidade) (problema #80)v1.1, 07/07/2018
--help
além de -h
-S
(commit)v1.0, 28/01/2018
--prefer
e --avoid
(@TomJohnZ)-n
e -N
v0.12: Adicionar opções -M
e -S
(@nailgun); adicionar página de manual, parametrizar Makefile (@yangfl)
v0.11: Corrige comportamento indefinido em get_entry_fatal (falta de retorno, commit)
v0.10: Permitir substituir a variável VERSION do Makefile para facilitar o empacotamento, adicionar a opção de linha de comando -v
v0.9: Se oom_score de todos os processos for 0, use VmRss para encontrar uma vítima
v0.8: Use uma estimativa se o kernel não fornecer MemAvailable
v0.7: Selecione a vítima por oom_score em vez de VmRSS, adicione as opções -i
e -d
v0.6: Adicionar opções de linha de comando -m
, -s
, -k
v0.5: Adicionar suporte de troca
v0.4: Adicione o script de inicialização SysV (obrigado @joeytwiddle), use o novo MemAvailable
de /proc/meminfo
(precisa de Linux 3.14+, commit)
v0.2: Adicionar arquivo de unidade systemd
v0.1: versão inicial