O Linux começará a matar meus processos sem me perguntar se a memória fica curta?

66

Eu estava executando um shell script com comandos para executar vários programas com muita memória (2 a 5 GB) consecutivos. Quando voltei para verificar o andamento do meu script, fiquei surpreso ao descobrir que alguns dos meus processos eram Killed, como meu terminal me informou. Vários programas já foram concluídos sucessivamente antes dos programas que foram Killediniciados posteriormente , mas todos os programas posteriormente falharam em uma falha de segmentação (que pode ou não ter sido devido a um bug no meu código, continue lendo).

Examinei o histórico de uso do cluster específico que estava usando e vi que alguém começou a executar vários processos com muita memória ao mesmo tempo e, ao fazê-lo, esgotou a memória real (e possivelmente até o espaço de troca) disponível para o cluster. Pelo melhor que pude imaginar, esses processos com muita memória começaram a ser executados na mesma época em que comecei a ter problemas com meus programas.

É possível que o Linux tenha matado meus programas quando começou a ficar sem memória? E é possível que as falhas de segmentação que obtive mais tarde sejam devidas à falta de memória disponível para executar meus programas (em vez de um erro no meu código)?

Estrêla de Neutróns
fonte
2
Ao alocar memória, você tem uma instrução para verificar se a memória foi alocada com êxito? Isso deve fornecer uma pista sobre se há um erro no seu código ou se foi devido à falta de memória no sistema.
unxnut

Respostas:

72

Pode.

Existem duas condições diferentes de falta de memória que você pode encontrar no Linux. O que você encontra depende do valor de sysctl vm.overcommit_memory( /proc/sys/vm/overcommit_memory)

Introdução:
O kernel pode executar o que é chamado de 'supercomprometimento de memória'. É quando o kernel aloca programas mais memória do que realmente está presente no sistema. Isso é feito na esperança de que os programas não usem toda a memória que eles alocaram, pois essa é uma ocorrência bastante comum.

overcommit_memory = 2

Quando overcommit_memoryestá definido como 2, o kernel não executa nenhuma confirmação excessiva. Em vez disso, quando um programa recebe memória, é garantido o acesso a essa memória. Se o sistema não tiver memória livre suficiente para satisfazer uma solicitação de alocação, o kernel retornará apenas uma falha para a solicitação. Cabe ao programa lidar normalmente com a situação. Se não verificar se a alocação foi bem-sucedida quando realmente falhou, o aplicativo geralmente encontrará um segfault.

No caso do segfault, você deve encontrar uma linha como esta na saída de dmesg:

[1962.987529] myapp[3303]: segfault at 0 ip 00400559 sp 5bc7b1b0 error 6 in myapp[400000+1000]

Os at 0meios que o aplicativo tentou acessar um ponteiro não inicializado, que pode ser o resultado de uma falha na chamada de alocação de memória (mas não é a única maneira).

overcommit_memory = 0 e 1

Quando overcommit_memoryestá definido como 0ou 1, a confirmação excessiva é ativada e os programas têm permissão para alocar mais memória do que realmente está disponível.

No entanto, quando um programa deseja usar a memória que foi alocada, mas o kernel descobre que na verdade não possui memória suficiente para satisfazê-lo, ele precisa recuperar alguma memória. Primeiro, ele tenta executar várias tarefas de limpeza de memória, como a limpeza de caches, mas se isso não for suficiente, encerrará um processo. Essa terminação é realizada pelo OOM-Killer. O OOM-Killer analisa o sistema para ver quais programas estão usando qual memória, há quanto tempo eles estão sendo executados, quem os executa e vários outros fatores para determinar qual deles é morto.

Depois que o processo é encerrado, a memória usada é liberada e o programa que acabou de causar a condição de falta de memória agora tem a memória necessária.

No entanto, mesmo nesse modo, os programas ainda podem receber pedidos de alocação negados. Quando overcommit_memoryé 0, o kernel tenta adivinhar quando deve começar a negar solicitações de alocação. Quando está definido como 1, não tenho certeza de qual determinação ele usa para determinar quando deve negar uma solicitação, mas pode negar solicitações muito grandes.

Você pode ver se o OOM-Killer está envolvido observando a saída de dmesge localizando mensagens como:

[11686.043641] Out of memory: Kill process 2603 (flasherav) score 761 or sacrifice child
[11686.043647] Killed process 2603 (flasherav) total-vm:1498536kB, anon-rss:721784kB, file-rss:4228kB
Patrick
fonte
Então, parece que as duas situações aconteceram comigo.
NeutronStar
@ Josué Acabei de atualizar a resposta. Eu esqueci de mencionar que você ainda pode obter falhas de alocação quando overcommit_memoryé definido como 0 ou 2.
Patrick
Acho que a edição de um link para domar o assassino do OOM no post pode valer a pena.
0xC0000022L 10/06
@ 0xC0000022L Obrigado, esse é um bom artigo (embora um pouco desatualizado). Eu não queria colocar nada sobre como controlar o assassino da OOM, já que isso não faz parte da pergunta (e não é um assunto curto), e temos várias outras perguntas aqui sobre isso.
Patrick
11
@ MikeServ Eu não digo que o comportamento do assassino OOM não tem nada a ver com controlá-lo. A questão era se o Linux mataria seus programas. Como impedir que o linux o faça primeiro, é necessário estabelecer que é realmente o Linux a fazê-lo. E se overcommit_memory=2o assassino de OOM não estiver ativado, então controlá-lo é irrelevante. No entanto, uma vez que estabelecemos que é o assassino da OOM, isso se torna outro assunto, abrangido por muitas outras perguntas e respostas aqui.
Patrick
16

A verdade é que, independentemente de como você olha para ele - se seu processo foi interrompido devido ao gerenciador de memória do sistema ou devido a alguma outra coisa - ainda é um bug. O que aconteceu com todos esses dados que você estava apenas processando na memória? Deveria ter sido salvo.

Embora overcommit_memory=seja a maneira mais geral de configurar o gerenciamento do Linux OOM, também é ajustável por processo, como:

echo [-+][n] >/proc/$pid/oom_adj

O uso -17do procedimento acima excluirá um processo do gerenciamento de falta de memória. Provavelmente não é uma boa ideia em geral, mas se você estiver caçando bugs, pode valer a pena - especialmente se você deseja saber se era OOM ou seu código. Aumentar positivamente o número aumentará a probabilidade de morte do processo em um evento de OOM, o que poderá permitir uma melhor resiliência do seu código em situações de pouca memória e garantir que você saia normalmente quando necessário.

Você pode verificar as configurações atuais do manipulador de OOM por processo, como:

cat /proc/$pid/oom_score 

Caso contrário, você poderia se suicidar:

sysctl vm.panic_on_oom=1
sysctl kernel.panic=X

Isso configurará o computador para reiniciar no caso de uma condição de falta de memória. Você define o Xnúmero acima para o número de segundos que deseja que o computador pare após um pânico no kernel antes de reiniciar. Enlouquecer.

E se, por algum motivo, você decidir que gosta, torne-o persistente:

echo "vm.panic_on_oom=1" >> /etc/sysctl.conf
echo "kernel.panic=X" >> /etc/sysctl.conf
mikeserv
fonte
É um cluster compartilhado que estou usando, tenho certeza que os outros usuários não gostariam que ele fosse reiniciado sem o consentimento deles.
NeutronStar
3
@ Josué - duvido muito seriamente que alguém queira - até desafia as leis da robótica de Asimov. Por outro lado, como mencionei, você também pode configurar o OOM por processo da outra maneira. Ou seja, você pode fazer uma triagem pessoal com base em seus próprios conjuntos de regras definidos por processo. Esse tipo de coisa parece ser especialmente útil em um cenário de cluster compartilhado.
mikeserv