Por alguma razão nosso sistema começa a trocar (memória usada ativamente) por cerca de 60GB de memória usada. (veja a edição abaixo, parece que o uso de E / S e do cache de disco, mesmo dos processos executados anteriormente, tem um efeito)
Desligá-lo ( swapoff-a
) para teste leva a bad_alloc uma vez (eu acho que porque havia mais processos também usando memória no momento), mas também trabalhou para acelerar o meu programa por um fator de mroe de 10.
Isso reproduz o problema (sem outros processos significativos executando o EDIT: veja abaixo, isso só acontece se um processo intenso de I / O foi executado pouco antes):
#include <cstdio>
#include <vector>
int main() {
size_t bytes = size_t(80) * 1024 * 1024 * 1024; // 80GB
size_t* data = new size_t[bytes / sizeof(size_t)];
for (size_t i = 0; i < bytes / sizeof(size_t); ++i) {
data[i] = i;
}
for (;;) {}
}
Com cerca de 60 GB de memória usada, o sistema inicia a troca e o uso da CPU fica abaixo de 100% (porque o processo está com E / S agora, eu acho).
O sistema é um Ubuntu 14.04, 64 bits:
Linux ... 3.13.0-77-generic #121-Ubuntu SMP Wed Jan 20 10:50:42 UTC 2016 x86_64 x86_64 x86_64 GNU/Linux
Quando o ponto for atingido, o que o free -m me dá:
total used free shared buff/cache available
Mem: 96671 55504 358 60 40808 40478
Swap: 47679 19366 28313
O problema persiste com o swappiness = 1 (se algo intensivo de E / S acabou de ser executado e especialmente para o meu culpado real (não o código acima) que faz ambos, muita E / S e usa muita memória. pouco ou nenhum I / O recentemente, o programa acima aloca toda a memória e não troca!
O problema desaparece se não houver nada de I / O intenso por mais tempo. Parece que o sistema operacional de alguma forma faz com que meu aplicativo troque porque ele acha que o cache de disco é mais valioso - mesmo com baixíssimo swap. Eu não entendo esse comportamento porque a memória cache de disco deve ser tão boa quanto a memória livre e certamente não acionar a troca no processo em execução.
Inicialmente, meu problema aconteceu em um aplicativo que lê arquivos grandes e usa muita memória. Depois disso, ele persiste no código de exemplo acima, que não possui nenhum I / O. Finalmente, quando eu iniciar o código de exemplo mais tarde, não haverá troca.