Isso parece ser um problema na combinação de dois fatores:
- Usando uma máquina virtual.
- Um possível erro no kernel.
Esta é, em parte, uma das linhas que descreve por que isso acontece:
Mar 7 02:43:11 myhost kernel: memcheck-amd64- invoked oom-killer: gfp_mask=0x24002c2, order=0, oom_score_adj=0
A outra linha é esta:
Mar 7 02:43:11 myhost kernel: 0 pages HighMem/MovableOnly
| A primeira linha é a máscara GFP atribuída para a alocação. Basicamente descreve o que o kernel é permitido / não permitido fazer para satificar este pedido.
A máscara indica um monte de sinalizadores padrão. O último bit, '2', no entanto, indica que a alocação de memória deve vir da HighMem
zone.
Se você observar atentamente a saída do OOM, verá que a HighMem/Normal
zone realmente existe.
Mar 7 02:43:11 myhost kernel: Node 0 DMA: 20*4kB (UM) 17*8kB (UM) 13*16kB (M) 14*32kB (UM) 8*64kB (UM) 4*128kB (M) 4*256kB (M) 0*512kB 1*1024kB (M) 0*2048kB 0*4096kB = 3944kB
Mar 7 02:43:11 myhost kernel: Node 0 DMA32: 934*4kB (UM) 28*8kB (UM) 0*16kB 0*32kB 0*64kB 0*128kB 0*256kB 0*512kB 0*1024kB 0*2048kB 0*4096kB = 3960kB
HighMem
(geralmente também chamado de Normal
on x86_64) tende a mapear memória para regiões fora dos intervalos padrão de 896 MiB diretamente do kernel em sistemas de 32 bits. Em x86_64 HighMem/Normal
parece cobrir todas as páginas acima do tamanho 3GiB.
DMA32
contém uma zona usada para memória que seria acessível em dispositivos DMA de 32 bits, ou seja, você pode endereçá-los com ponteiros de 4 bytes. Eu acredito que DMA
é para dispositivos DMA de 16 bits.
Em geral, em sistemas com pouca memória Normal
não existiria, já que DMA32
abrange todos os endereços virtuais disponíveis.
A razão pela qual você OOM mata é porque há uma alocação de memória para uma zona HighMem
com 0 páginas disponíveis. Dado o manipulador de falta de memória não tem absolutamente nenhuma maneira de satisfazer fazendo esta zona ter páginas para usar trocando, matando outros processos ou qualquer outro truque, o OOM-killer apenas mata.
Acredito que isso seja causado pelo balão VM da VM durante a inicialização. Nos sistemas KVM, existem dois valores que você pode definir.
- A memória atual.
- A memória disponível.
A maneira como isso funciona é que você pode adicionar memória ao seu servidor até a memória disponível. Seu sistema, no entanto, recebe a memória atual.
Quando uma VM KVM é inicializada, ela começa com a quantidade máxima de memória possível (a memória disponível). Gradualmente, durante a fase de inicialização do sistema, o KVM recupera essa memória usando seu balão, deixando você com a configuração de memória atual que você possui.
É minha crença que é o que aconteceu aqui. Linode permite expandir a memória, dando muito mais no início do sistema.
Isso significa que há uma Normal/HighMem
zone no início da vida útil do sistema. Quando o hypervisor o libera, a zona normal desaparece corretamente do gerenciador de memória. Mas, eu suspeito que o sinalizador definindo se a dita zona está disponível para alocar não é não desmarcada quando deveria. Isso leva o kernel a tentar alocar de uma região que não existe.
Em termos de resolver isso, você tem duas opções.
-
Traga isso para as listas de discussão do kernel para ver se isso realmente é um bug, comportamento esperado ou nada a ver com o que estou dizendo.
-
Solicite que o linode defina a 'memória disponível' no sistema para ser a mesma atribuição de 1GiB que a 'memória atual'. Assim, o sistema nunca faz balões e nunca recebe uma zona Normal na inicialização, mantendo a sinalização clara. Boa sorte para eles fazerem isso!
Você deve ser capaz de testar se este é o caso configurando sua própria VM na configuração KVM disponível para 6GiB, atual para 1GiB e executando seu teste usando o mesmo kernel para ver se esse comportamento que você vê acima ocorre. Se isso acontecer, altere a configuração 'disponível' para igualar a corrente de 1GiB e repita o teste.
Estou fazendo um monte de suposições aqui e lendo as linhas entre as linhas para chegar a essa resposta, mas o que estou dizendo parece se encaixar nos fatos já descritos.
Sugiro testar minha hipótese e deixar que todos saibam o resultado.