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

57

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

Eu olhei para o histórico de uso do cluster em particular que eu estava usando e vi que alguém começou a executar vários processos intensivos de memória ao mesmo tempo e, ao fazê-lo, esgotou a memória real (e possivelmente até o espaço de swap) disponível para o grupo. Por melhor que eu possa imaginar, esses processos intensivos de memória começaram a rodar mais ou menos 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 recebi mais tarde se devam à falta de memória disponível para executar meus programas (em vez de um bug no meu código)?

    
por Joshua 10.06.2014 / 00:42

2 respostas

64

Pode.

Existem 2 condições diferentes 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 a que está realmente presente no sistema. Isso é feito na esperança de que os programas não usem realmente toda a memória que alocaram, já que é uma ocorrência bastante comum.

overcommit_memory = 2

Quando overcommit_memory é definido como 2 , o kernel não executa nenhuma supercompra. 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 um pedido de alocação, o kernel apenas retornará uma falha para o pedido. Cabe ao programa lidar com a situação. Se não verificar que a alocação foi bem-sucedida quando realmente falhou, o aplicativo frequentemente encontrará um segfault.

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

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

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

overcommit_memory = 0 e 1

Quando overcommit_memory é definido como 0 ou 1 , a supercomprometimento é ativada e os programas podem alocar mais memória do que realmente disponível.

No entanto, quando um programa quer usar a memória que foi alocada, mas o kernel descobre que ele não tem memória suficiente para satisfazê-lo, ele precisa recuperar alguma memória.
Ele primeiro tenta executar várias tarefas de limpeza de memória, como liberar caches, mas se isso não for suficiente, terminará um processo. Essa rescisão é realizada pelo OOM-Killer. O OOM-Killer olha para o sistema para ver quais programas estão usando qual memória, por quanto tempo eles estão rodando, quem os está executando, e uma série de outros fatores para determinar qual deles será morto.

Após o processo ser eliminado, a memória que estava sendo utilizada é liberada, e o programa que acabou de causar a condição de falta de memória agora possui a memória necessária.

No entanto, mesmo nesse modo, os programas ainda podem receber solicitações de alocação negadas. Quando overcommit_memory é 0 , o kernel tenta adivinhar quando deve começar a negar solicitações de alocação. Quando é 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 olhando a saída de demsg e encontrando uma mensagem 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
    
por 10.06.2014 / 00:56
14

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

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

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

Usar -17 nos itens acima excluirá um processo do gerenciamento de falta de memória. Provavelmente não é uma ótima idéia em geral, mas se você estiver caçando bugs, isso pode valer a pena - especialmente se você quiser saber se era OOM ou seu código. O incremento positivo do número tornará o processo mais provável de ser eliminado em um evento OOM, o que poderia permitir que você aprimore melhor a resiliência do seu código em situações de pouca memória e garanta a saída normal quando necessário.

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

cat /proc/$pid/oom_score 

Se você fosse suicida:

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

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

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

echo "vm.panic_on_oom=1" >> /etc/sysctl.conf
echo "kernel.panic=X" >> /etc/sysctl.conf
    
por 10.06.2014 / 01:02