evitar congelamento / falta de resposta do sistema devido à troca do uso da memória de fuga

48

Se um processo exigir muita memória, o sistema move todos os outros processos para o arquivo de troca. Incluindo, parece, processos necessários, como o servidor X11 ou o terminal.

Portanto, se um processo continua alocando sem limite, tudo fica sem resposta, até que esse processo seja morto pelo assassino de OOM. Meu laptop parece ser especialmente sensível e reage extremamente mal. Passei uma HORA INTEIRA aguardando o término do processo durante o qual nem o cursor do mouse poderia ser movido.

Como isso pode ser evitado?

1) Desative a troca => Geralmente inicio muitos processos que ficam inativos. Os inativos devem ser movidos para a troca.

2) Consiga um SSD => muito caro

3) defina um máximo de memória ulimit =>, mas falhará nos casos em que um programa precise de uma quantidade grande e razoável de memória. o problema não é que ele usa muito, mas suprime os outros processos

4) mantenha programas importantes (X11, bash, kill, top, ...) na memória e nunca troque esses => isso pode ser feito? quão? talvez apenas troque programas grandes?

5)

BeniBela
fonte
E ti aconteceu gcc novamente :( Iniciado enquanto o Firefox estava correndo, tudo foi bloqueada por meia hora movimento No rato, nenhuma leitura ebook.
BeniBela
Não sei se entendi o que você quer. Deseja que o sistema faça magicamente as coisas mais rapidamente com os recursos que possui? Deseja que ele acabe com processos que usam muita memória antes?
David Schwartz #
Parece que você realmente precisa de mais RAM. Ou menos tarefas em segundo plano "inativas".
Daniel B
2
Você pode usar a combinação de teclas Alt + SysRq + F para forçar a execução do OOM-killer. Isso pode reduzir o tempo ridículo necessário para aguardar o sistema abrir um console para que você possa matar um processo.
hololeap
Corrija-me se eu estiver errado, mas esse problema realmente parece que o sistema está procurando por espaço de troca de disco que deveria existir, mas não existe (a partição de troca é muito pequena). Um espaço de troca insuficiente resultará no sistema "debulhando" o disco rígido (ou ssd) procurando espaço disponível.
Mchid 18/0318

Respostas:

45

TL; DR

Temporário / resposta curta

  • Mais fácil : tenha uma partição de troca menor e evite que o kernel tente cumprir a mentira de que não há limite de memória executando processos a partir do armazenamento lento.
    • Com uma grande troca, o OOM (gerenciador de falta de memória) não toma ação logo. Normalmente, ele é contabilizado de acordo com a memória virtual e, na minha experiência anterior, não matou as coisas até que todo o swap fosse preenchido, daí o sistema de debulhar e rastrear ...
  • Precisa de uma grande troca de hibernação?
    • Tentativa / problemático : defina alguns limites (por exemplo ulimit -v, verifique e talvez defina um limite rígido ou flexível usando a asopção in limits.conf). Isso costumava funcionar bem o suficiente, mas graças à introdução do WebKit gigacage, muitos aplicativos gnome agora esperam espaços de endereço ilimitados e não conseguem executar!
    • Tentativa / problemática : A política overcommit ea razão é outra maneira de tentar gerenciar e mitigar isso (por exemplo sysctl vm.overcommit_memory, sysctl vm.overcommit_ratio, mas esta abordagem não deu certo para mim.
    • Difícil / complicado : tente aplicar uma prioridade do cgroup aos processos mais importantes (por exemplo, ssh), mas atualmente isso parece complicado para o cgroup v1 (espero que v2 facilite) ...

Eu também encontrei:

Solução a longo prazo

espere e espere que alguns patches upstream entrem em kernels de distribuição estáveis. Também esperamos que os fornecedores de distribuição melhor sintonizem os padrões do kernel e alavancem melhor os grupos de sistemas para priorizar a capacidade de resposta da GUI nas edições de desktop.

Alguns patches de interesse:

Portanto, não é apenas um código de espaço do usuário ruim e as configurações / padrões da distro que estão com defeito - o kernel poderia lidar com isso melhor.

Comentários sobre opções já consideradas

1) Desativar a troca

É recomendável fornecer pelo menos uma pequena partição de troca ( realmente precisamos de troca em sistemas modernos? ). Desabilitar a troca não apenas impede a troca de páginas não utilizadas, mas também pode afetar a estratégia de supercompressão heurística padrão do kernel para alocar memória (o que significa heurística em Overcommit_memory = 0 significa? ), Pois essa heurística conta com páginas de troca. Sem troca, a supercompromisso ainda pode provavelmente funcionar nos modos heurístico (0) ou sempre (1), mas a combinação da estratégia de não troca e da nunca (2) supercomprovação provavelmente é uma péssima idéia. Portanto, na maioria dos casos, nenhuma troca provavelmente prejudicará o desempenho.

Por exemplo, pense em um processo de execução demorada que inicialmente toque na memória para trabalho único, mas que falhe ao liberar essa memória e continue executando o plano de fundo. O kernel precisará usar a RAM para isso até o processo terminar. Sem nenhuma troca, o kernel não pode paginar por outra coisa que realmente queira usar a RAM ativamente. Pense também em quantos desenvolvedores são preguiçosos e não liberam explicitamente a memória após o uso.

3) definir um limite máximo de memória

Aplica-se apenas por processo, e provavelmente é uma suposição razoável de que um processo não deva solicitar mais memória que um sistema possui fisicamente! Portanto, é provavelmente útil impedir que um processo louco e solitário desencadeie uma surra enquanto ainda está sendo generosamente definido.

4) mantenha programas importantes (X11, bash, kill, top, ...) na memória e nunca troque

Boa ideia, mas esses programas consumirão memória que não estão sendo usados ​​ativamente. Pode ser aceitável se o programa solicitar apenas uma quantidade modesta de memória.

A versão systemd 232 acabou de adicionar algumas opções que tornam isso possível: Eu acho que alguém poderia usar o 'MemorySwapMax = 0' para impedir que uma unidade (serviço) como o ssh tenha sua memória trocada.

No entanto, ser capaz de priorizar o acesso à memória seria melhor.

Explicação longa

O kernel do linux é mais otimizado para as cargas de trabalho do servidor, portanto a capacidade de resposta da GUI infelizmente foi uma preocupação secundária ... As configurações de gerenciamento de memória do kernel na edição para desktop do Ubuntu 16.04 LTS não pareciam diferir das outras edições do servidor. Ele ainda corresponde aos padrões no RHEL / CentOS 7.2 normalmente usados ​​como servidor.

OOM, ulimit e troca de integridade por capacidade de resposta

A troca de trocas (quando o conjunto de memória de trabalho, ou seja, as páginas que estão sendo lidas e gravadas em um determinado período de tempo excede a RAM física) sempre bloqueia a E / S de armazenamento - nenhuma mágica do kernel pode salvar um sistema disso sem interromper um processo ou dois...

Espero que os ajustes do OOM do Linux que surjam nos kernels mais recentes reconheçam que este conjunto de trabalho excede a situação da memória física e mata um processo. Quando isso não acontece, o problema surra. O problema é que, com uma grande partição de swap, pode parecer que o sistema ainda possui espaço livre enquanto o kernel se compromete e ainda atende solicitações de memória, mas o conjunto de trabalho pode se espalhar para o swap, tratando efetivamente o armazenamento como se é RAM.

Nos servidores, ele aceita a penalidade de desempenho do thrashing para uma troca determinada, lenta e sem perda de dados. Nos desktops, a troca é diferente e os usuários preferem um pouco de perda de dados (sacrifício de processos) para manter as coisas responsivas.

Essa foi uma boa analogia cômica sobre OOM: oom_pardon, aka não mate meu xlock

Aliás, OOMScoreAdjusté outra opção do sistema para ajudar a pesar e evitar processos de destruição de OOM considerados mais importantes.

write-back com buffer

Eu acho que " Fazer a gravação em segundo plano não ser uma merda " ajudará a evitar alguns problemas nos quais um processo que monopoliza a RAM causa outra troca (gravação em disco) e a gravação em massa no disco interrompe qualquer outra coisa que deseje IO. Não é a causa do problema em si, mas contribui para a degradação geral da capacidade de resposta.

limitação ulimits

Um problema com ulimits é que o limite de contabilidade se aplica ao espaço de endereço da memória virtual (o que implica combinar o espaço físico e o swap). Conforme man limits.conf:

       rss
          maximum resident set size (KB) (Ignored in Linux 2.4.30 and
          higher)

Portanto, definir um ulimit para aplicar apenas ao uso físico da RAM não parece mais utilizável. Conseqüentemente

      as
          address space limit (KB)

parece ser o único respeitável sintonizador.

Infelizmente, conforme detalhado no exemplo do WebKit / Gnome, alguns aplicativos não podem ser executados se a alocação de espaço de endereço virtual for limitada.

cgroups deve ajudar no futuro?

Atualmente, parece complicado, mas é possível ativar alguns sinalizadores de cgroup do kernel cgroup_enable=memory swapaccount=1(por exemplo, na configuração do grub) e tente usar o controlador de memória cgroup para limitar o uso da memória.

O cgroups possui recursos de limite de memória mais avançados que as opções 'ulimit'. As notas do CGroup v2 sugerem tentativas de melhorar o funcionamento dos ulimits.

A memória combinada + contabilidade e limitação de swap são substituídas pelo controle real sobre o espaço de swap.

As opções do CGroup podem ser definidas através das opções de controle de recursos do systemd . Por exemplo:

  • MemoryHigh
  • MemoryMax

Outras opções úteis podem ser

  • IOWeight
  • CPUShares

Estes têm alguns inconvenientes:

  1. A sobrecarga. A documentação atual da janela de encaixe menciona brevemente 1% de uso extra de memória e 10% de degradação do desempenho (provavelmente em relação às operações de alocação de memória - ela realmente não especifica).
  2. As coisas do Cgroup / systemd foram pesadamente re-trabalhadas recentemente, então o fluxo upstream implica que os distribuidores de Linux podem estar esperando a solução primeiro.

No CGroup v2 , eles sugerem que memory.highdeve ser uma boa opção para controlar e gerenciar o uso de memória por um grupo de processos. No entanto, esta citação sugere que o monitoramento de situações de pressão de memória precisava de mais trabalho (a partir de 2015).

Uma medida da pressão da memória - quanto a carga de trabalho está sendo afetada devido à falta de memória - é necessária para determinar se uma carga de trabalho precisa de mais memória; infelizmente, o mecanismo de monitoramento da pressão da memória ainda não foi implementado.

Dado que as ferramentas de espaço do usuário systemd e cgroup são complexas, não encontrei uma maneira simples de definir algo apropriado e aproveitar isso ainda mais. A documentação do cgroup e systemd para o Ubuntu não é ótima. O trabalho futuro deve ser para distros com edições de desktop para alavancar cgroups e systemd, para que, sob alta pressão de memória, os componentes ssh e X-Server / gerenciador de janelas tenham acesso de maior prioridade à CPU, RAM física e E / S de armazenamento, para evitar competir com os processos troca ocupada. Os recursos de prioridade de E / S da CPU e do kernel já existem há algum tempo. Parece ser o acesso prioritário à RAM física que está faltando.

No entanto, nem mesmo as prioridades de CPU e E / S estão definidas adequadamente !? Quando verifiquei os limites do systemd cgroup, os compartilhamentos da CPU, etc. aplicados, até onde eu sabia, o Ubuntu não havia funcionado em nenhuma priorização predefinida. Por exemplo, eu corri:

systemctl show dev-mapper-Ubuntu\x2dswap.swap

Comparei isso com a mesma saída para ssh, samba, gdm e nginx. Coisas importantes, como a GUI e o console de administração remota, têm que lutar igualmente com todos os outros processos quando ocorre a debulha.

Limites de memória de exemplo que tenho em um sistema de 16 GB de RAM

Eu queria ativar a hibernação, então precisava de uma grande partição de troca. Daí a tentativa de mitigar com ulimits, etc.

ulimit

Eu coloquei * hard as 16777216de /etc/security/limits.d/mem.conftal forma que nenhum processo único poderia solicitar mais memória do que é fisicamente possível. Não evitarei debater todos juntos, mas sem isso, apenas um único processo com uso de memória ganancioso, ou um vazamento de memória, pode causar debulha. Por exemplo, eu vi gnome-contactsconsumir mais de 8 GB de memória ao fazer coisas comuns, como atualizar a lista de endereços global de um servidor de troca ...

Contatos do Gnome consumindo RAM

Como visto ulimit -S -v, muitas distros têm esse limite rígido e flexível definido como "ilimitado", dado que, em teoria, um processo pode acabar solicitando muita memória, mas apenas ativamente usando um subconjunto, e rodando feliz pensando que foi concedido, digamos, 24 GB de RAM enquanto o sistema possui apenas 16 GB. O limite rígido acima fará com que os processos que podem ter sido capazes de executar corretamente sejam interrompidos quando o kernel negar suas solicitações de memória especulativa gananciosas.

No entanto, ele também captura coisas insanas, como contatos do gnome, e em vez de perder a capacidade de resposta da minha área de trabalho, recebo o erro "memória insuficiente":

insira a descrição da imagem aqui

Complicações configurando ulimit para espaço de endereço (memória virtual)

Infelizmente, alguns desenvolvedores gostam de fingir que a memória virtual é um recurso infinito e definir um limite na memória virtual pode quebrar alguns aplicativos. Por exemplo, o WebKit (do qual alguns aplicativos gnome dependem) adicionou um gigacagerecurso de segurança que tenta alocar quantidades insanas de memória virtual e FATAL: Could not allocate gigacage memoryerros com uma dica atrevida Make sure you have not set a virtual memory limit. A solução alternativa,GIGACAGE_ENABLED=norenuncia aos benefícios de segurança, mas, da mesma forma, não é permitido limitar a alocação de memória virtual também renuncia a um recurso de segurança (por exemplo, controle de recursos que pode impedir a negação de serviço). Ironicamente, entre os desenvolvedores de gigacage e gnome, eles parecem esquecer que limitar a alocação de memória é um controle de segurança. E, infelizmente, notei que os aplicativos gnome que dependem de gigacage não se preocupam em solicitar explicitamente um limite mais alto; portanto, mesmo um limite suave interrompe as coisas nesse caso.

Para ser justo, se o kernel fez um trabalho melhor em negar a alocação de memória com base no uso da memória residente em vez da memória virtual, fingir que a memória virtual é ilimitada seria menos perigoso.

comprometer

Se você preferir que os aplicativos tenham acesso negado à memória e queira interromper o comprometimento excessivo, use os comandos abaixo para testar como o sistema se comporta quando está sob alta pressão de memória.

No meu caso, a taxa de confirmação padrão era:

$ sysctl vm.overcommit_ratio
vm.overcommit_ratio = 50

Mas isso só entra em vigor ao alterar a política para desativar o excesso de confirmação e aplicar a taxa

sudo sysctl -w vm.overcommit_memory=2

A proporção implicada em que apenas 24 GB de memória pode ser alocada no geral (16 GB de RAM * 0,5 + 16 GB de SWAP). Portanto, eu provavelmente nunca veria o OOM aparecer, e seria menos provável que os processos acessassem constantemente a memória em troca. Mas provavelmente também sacrificarei a eficiência geral do sistema.

Isso fará com que muitos aplicativos travem, pois é comum que os desenvolvedores não manejem normalmente o sistema operacional que recusa uma solicitação de alocação de memória. Ele elimina o risco ocasional de um bloqueio prolongado devido a surtos (solte todo o seu trabalho após uma reinicialização forçada) a um risco mais frequente de vários aplicativos travarem. Nos meus testes, não ajudou muito porque a própria área de trabalho travou quando o sistema estava sob pressão de memória e não pôde alocar memória. No entanto, pelo menos consoles e SSH ainda funcionavam.

Como a VM supercomprime a memória funciona tem mais informações.

Eu escolhi voltar ao padrão para isso, sudo sysctl -w vm.overcommit_memory=0considerando toda a pilha gráfica da área de trabalho e os aplicativos nela travados.

JPvRiel
fonte
4
Este é o melhor artigo que eu já vi sobre o assunto e você não recorre a "apenas comprar mais RAM!" Uma coisa que você não menciona é como as opções de configuração do kernel se encaixam nisso. Por exemplo, o modelo de preempção usado ou o planejador de E / S usado teriam algum efeito importante nisso?
hololeap
2
but the kernel won't be able to use an overcommit strategy for allocating memory and this will likely hurt performance. Even a smaller swap partition allows this. Existe alguma prova disso? Acredito overcommits do kernel muito bem sem troca configurado
Ygrek
@ygrek, obrigado, essa redação parece um pouco errada - a supercomissão ainda funciona sem troca, a menos que o modo de nunca supercomprimir (2) seja escolhido. Os modos de supercomprometimento heurístico padrão (0) ou sempre confirmar (1) provavelmente ainda funcionam sem troca. Não me lembro onde li que desativar a troca prejudica a capacidade do código de confirmação excessiva de alocar memória (e qual modo foi afetado especificamente). Pesquisei no Google novamente sem sorte, mas este foi um post semi-útil: stackoverflow.com/questions/38688824/… Vou editar a resposta adequadamente.
JPvRiel 21/09
Eu esperava que o patch de write-back em segundo plano me ajudasse, mas estou em um kernel muito novo (4.14.81) e enfrento consideráveis ​​problemas de capacidade de resposta em E / S de disco pesada (independentemente de a troca ser a causa ou não). Gostaria de saber se o gerenciador de dispositivos ou minha criptografia LUKS estão causando problemas de desempenho de alguma forma. Eu realmente tenho pouca idéia de como depurar esse tipo de problema.
Darius Jahandarie 29/11