Como interrompo rapidamente um processo que está causando problemas (devido ao excesso de alocação de memória)?

19

Todos nós já experimentamos - é solicitado a algum programa que faça algo que exija uma quantidade enorme de memória. Ele obedientemente tenta alocar toda essa memória, e o sistema imediatamente começa a se debater, trocando sem parar e ficando lento ou sem resposta.

Mais recentemente, experimentei isso no meu laptop Ubuntu devido a um script do Matlab tentando alocar uma matriz ridiculamente grande. Depois de mais de 5 minutos de debatida, consegui fazer o Ctrl-F1 em um console e matar o Matlab. Eu preferiria ter alguma tecla de atalho que me desse o controle do sistema imediatamente e me permitisse matar o processo ofensivo; ou, talvez, simplesmente se recuse silenciosamente a alocar um buffer tão grande.

  1. Qual é a maneira mais rápida de recuperar o controle de um sistema Linux que não responde ou é extremamente lento devido à troca excessiva?

  2. Existe uma maneira eficaz de impedir que essa troca ocorra em primeiro lugar, por exemplo, limitando a quantidade de memória que um processo pode tentar alocar?

nibot
fonte

Respostas:

12

Pressione Alt-SysRq-F para interromper o processo usando mais memória:

  • A chave SysRq geralmente é mapeada para a tecla Imprimir.
  • Se você estiver usando uma área de trabalho gráfica, pode ser necessário pressionar Ctrl-Alt-SysRq-F , caso pressionar Alt-SysRq desencadeie outra ação (por exemplo, programa de instantâneos).
  • Se você estiver usando um laptop, talvez seja necessário pressionar uma tecla de função.
  • Para mais informações, leia o artigo da Wikipedia .
gracejo
fonte
5

Eu criei um script para esse fim - https://github.com/tobixen/thrash-protect

Eu tive esse script em execução em servidores de produção, estações de trabalho e laptops com sucesso. Esse script não mata os processos, mas os suspende temporariamente - tive várias situações mais tarde, nas quais tenho certeza de que havia perdido o controle devido a problemas se não fosse por esse script simples. No "pior caso", o processo incorreto será muito lento e, no final, será morto pelo kernel (OOM); no "melhor" caso, o processo incorreto será realmente concluído ... em qualquer caso, o servidor ou a estação de trabalho permanecerá relativamente responsivo, facilitando a investigação da situação.

Obviamente, "comprar mais memória" ou "não usar swap" são duas alternativas, respostas mais tradicionais à pergunta "como evitar a surra?", Mas em geral elas tendem a não funcionar tão bem (instalar mais memória pode por não ser trivial, um processo não autorizado pode consumir toda a memória, independentemente da quantidade instalada, e pode haver problemas de debulhar mesmo sem troca quando não há memória suficiente para armazenar em buffer / cache). Eu recomendo thrash-protect mais muito espaço de troca.

tobixen
fonte
Sobre a desativação da troca, de acordo com unix.stackexchange.com/a/24646/9108 , pode não ser a melhor opção.
sashoalm 5/09/16
De fato, alguém comentou o mesmo sobre mim, então eu modifiquei o documento de proteção contra thrash naquele momento.
tobixen
4
  1. Qual é a maneira mais rápida de recuperar o controle de um sistema Linux que não responde ou é extremamente lento devido à troca excessiva?

Já respondeu acima com Alt-SysRq-F

  1. Existe uma maneira eficaz de impedir que essa troca ocorra em primeiro lugar, por exemplo, limitando a quantidade de memória que um processo pode tentar alocar?

Estou respondendo a esta 2ª parte. Sim, ulimitainda funciona bem o suficiente para limitar um único processo. Você pode:

  • defina um limite flexível para um processo que você sabe que provavelmente ficará fora de controle
  • defina um limite rígido para todos os processos, se você desejar um seguro extra

Além disso, como mencionado brevemente:

Você pode usar o CGroups para limitar o uso de recursos e evitar esses problemas

De fato, o cgroups oferece controle mais avançado, mas atualmente é mais complicado de configurar na minha opinião.

Ulimit da velha escola

Uma vez desligado

Aqui está um exemplo simples:

$ bash
$ ulimit -S -v $((1*2**20))
$ r2(){r2 $@$@;};r2 r2
bash: xmalloc: .././subst.c:3550: cannot allocate 134217729 bytes (946343936 bytes allocated)

Isto:

  • Define um limite flexível de 1 GB de uso geral de memória (ulimit assume limite na unidade de kB)
  • Executa uma chamada de função bash recursiva r2(){ r2 $@$@;};r2 r2que exponencialmente consumirá CPU e RAM, dobrando-se infinitamente enquanto solicita memória da pilha.

Como você pode ver, ele foi interrompido ao tentar solicitar mais de 1 GB.

Observe que -vopera na alocação de memória virtual (total, ou seja, físico + swap).

Protecção permanente

Para limitar a alocação de memória virtual, asé o equivalente a -vpara limits.conf.

Eu faço o seguinte para proteger contra qualquer processo de comportamento inadequado:

  • Defina um limite de espaço de endereço físico para todos os processos.
  • address space limit = <physical memory> - 256MB.
  • Portanto, nenhum processo único com uso de memória ganancioso ou um loop ativo e vazamento de memória pode consumir TODA a memória física.
  • Há 256 MB de espaço livre para processamento essencial com ssh ou console.

Um forro:

$ sudo bash -c "echo -e \"*\thard\tas\t$(($(grep -E 'MemTotal' /proc/meminfo | grep -oP '(?<=\s)\d+(?=\skB$)') - 256*2**10))\" > /etc/security/limits.d/mem.conf"

Para validar, isso resulta no seguinte (por exemplo, no sistema de 16 GB):

$ cat /etc/security/limits.d/mem.conf
*   hard    as      16135196
$ ulimit -H -v
161351960

Notas:

  • Atenua apenas um único processo que exagere no uso de memória.
  • Não impedirá que uma carga de trabalho de vários processos com alta pressão de memória cause batidas (o cgroups é a resposta).
  • Não use a rssopção em limits.conf. Não é respeitado pelos kernels mais recentes.
  • É conservador.
    • Em teoria, um processo pode solicitar especulativamente muita memória, mas apenas usar ativamente um subconjunto (menor conjunto de trabalho / uso de memória residente).
    • O limite rígido acima fará com que esses processos sejam interrompidos (mesmo que, caso contrário, eles tenham sido executados corretamente, pois o Linux permite que o espaço de endereço da memória virtual seja supercomprometido).

Grupos CG mais recentes

Oferece mais controle, mas atualmente é mais complexo de usar:

  • Melhora na oferta ulimit.
    • memory.max_usage_in_bytes pode contabilizar e limitar a memória física separadamente.
    • Considerando que ulimit -me / ou rssin limits.conffoi criado para oferecer funcionalidade semelhante, mas isso não funciona desde o kernel Linux 2.4.30!
  • Necessidade de permitir algumas bandeiras do kernel cgroup em bootloader: cgroup_enable=memory swapaccount=1.
    • Isso não aconteceu por padrão no Ubuntu 16.04.
    • Provavelmente devido a algumas implicações no desempenho de despesas extras de contabilidade.
  • O material do cgroup / systemd é relativamente novo e está mudando bastante, então o fluxo upstream implica que os distribuidores de distribuição do Linux ainda não tornaram fácil o uso. Entre 14.04LTS e 16.04LTS, as ferramentas de espaço do usuário para usar cgroups foram alteradas.
    • cgm agora parece ser a ferramenta de espaço de usuário oficialmente suportada.
    • os arquivos de unidade systemd ainda não parecem ter nenhum padrão "vendor / distro" predefinido para priorizar serviços importantes como o ssh.

Por exemplo, para verificar as configurações atuais:

$ echo $(($(cat /sys/fs/cgroup/memory/memory.max_usage_in_bytes) / 2**20)) MB
11389 MB
$ cat /sys/fs/cgroup/memory/memory.stat
...

Por exemplo, para limitar a memória de um único processo:

$ cgm create memory mem_1G
$ cgm setvalue memory mem_1G memory.limit_in_bytes $((1*2**30))
$ cgm setvalue memory mem_1G memory.memsw.limit_in_bytes $((1*2**30))
$ bash
$ cgm movepid memory mem_1G $$
$ r2(){ r2 $@$@;};r2 r2
Killed

Para vê-lo em ação, mastigando a RAM como um processo em segundo plano e sendo morto:

$ bash -c 'cgm movepid memory mem_1G $$; r2(){ r2 $@$@;};r2 r2' & while [ -e /proc/$! ]; do ps -p $! -o pcpu,pmem,rss h; sleep 1; done
[1] 3201
 0.0  0.0  2876
 102  0.2 44056
 103  0.5 85024
 103  1.0 166944
 ...
98.9  5.6 920552
99.1  4.3 718196
[1]+  Killed                  bash -c 'cgm movepid memory mem_1G $$; r2(){ r2 $@$@;};r2 r2'

Observe o crescimento exponencial (potência de 2) nas solicitações de memória.

No futuro, esperamos ver "distro / vendors" pré-configurar prioridades e limites do cgroup (via unidades systemd) para coisas importantes como SSH e a pilha gráfica, para que eles nunca fiquem com falta de memória.

JPvRiel
fonte
2

Você pode pressionar Ctrl- zpara suspender o programa. Você pode fazer kill %1(ou qualquer que seja o número do trabalho ou usar o PID).

Você pode usar o ulimitcomando para tentar limitar a quantidade de memória disponível para um processo.

Pausado até novo aviso.
fonte
Ctrl-Z é bom, mas geralmente eu estou executando uma interface gráfica do Matlab e perdi o controle do terminal de controle, portanto, não há maneira fácil de emitir a tecla Ctrl-Z. Seria bom se a GUI tivesse uma tecla de atalho para enviar o SIGSTOP para qualquer aplicativo em foco!
Nibot
Você pode executar o kill -STOP <pid>que fará o mesmo que Ctrl-Z.
hlovdal 24/02
Sim, mas o problema é que, nessa situação, o sistema não responde tão bem que leva muito tempo (ou para sempre) para chegar a um prompt de comando.
Nibot
1

Você pode usar o CGroups para limitar o uso de recursos e evitar esses problemas: https://en.wikipedia.org/wiki/Cgroups

1kenthomas
fonte
Inclua as informações essenciais em sua resposta e use o link apenas para atribuição e leitura adicional. Esse link descreve o que é o CGroups, mas não é óbvio pelo link como realmente usá-lo para resolver o problema. Você pode expandir sua resposta para descrever a solução da pergunta? Obrigado.
Fixer1234
0

Seria bom se a GUI tivesse uma tecla de atalho para enviar o SIGSTOP para qualquer aplicativo em foco!

Sempre existe o xkillcomando clássico (do xorg-x11-apps-7.4-14.fc14.src.rpm no meu sistema). Eu acho que não deve ser muito difícil criar um clone que envie o SIGSTOP em vez de matar a janela de destino.

hlovdal
fonte
Como posso fazer o xkill iniciar rapidamente pressionando alguma combinação de teclas?
Nibot
Não tenho certeza. Presumo que o gnome e o KDE tenham alguma funcionalidade de atalho global que pode ser usada para iniciar programas.
hlovdal 24/02