
Um de nossos sistemas SAP (pilha PI ABAP + JAVA) estava apresentando problemas de desempenho. Todos os 64 GB configurados para a máquina ficam sobrecarregados (e os 8 núcleos também). Todo mundo está suspeitando da parte java, mas penso diferente.
Os nós do servidor Java foram reiniciados com erro de falta de memória. Olhando para os arquivos hprof, descobri que eles tinham apenas 1,2 G (média de 3 nós de servidor) de tamanho, quando 3 GB (-Xms e Xmx) de heap estão configurados para os nós do servidor. Esta observação levou à seguinte dúvida.
Eu li que quando Xms e Xmx são definidos com o mesmo valor, o jvm recebe todo o heap quando é iniciado. Se for o caso, os nós do servidor teriam 3 GB de heap desde o início. Se sim, por que isso não reflete no arquivo hprof ou se o hprof contém apenas a memória alocada para objetos durante o tempo de execução, o tamanho indica claramente que a memória heap estava livre (mais de 50%), então como erro OOM. ..!!..??
Eu também sei que o Linux faz algo chamado over-commit de memória. ou seja, a memória não é realmente fornecida quando é solicitada, mas quando é realmente usada. Isso está contribuindo para a exceção de falta de memória? Como quando a JVM inicia, o sistema operacional diz que você recebeu 3 GB de memória, mas na verdade adia até que seja realmente necessário. No momento em que a JVM realmente tenta alocar memória para objetos, alguns outros aplicativos podem ter esgotado a memória. Isso é possível...??
Mesmo que os nós Java tivessem problemas de vazamento de memória, não estariam confinados aos 3 GB de heap. Como ele pode consumir todos os 64G de memória física....???
Mais uma coisa que observei foi que o espaço de troca estava apenas 50% utilizado.
Alguma luz sobre isso...!
Responder1
O SAP OSS também estava investigando o problema. Hoje recebi a resposta deles. Minha observação estava correta. Java não foi o culpado. A pilha ABAP estava enfrentando algum problema e não liberando memória. Após reiniciar o processo de trabalho ABAP, a memória foi liberada no nível do sistema operacional.
Mas eu também gostaria de entender a parte destacada da questão, como se tal situação pode ocorrer ou não, resultando em erros JAVA OOM...??..!!. Qualquer informação a esse respeito será útil.
Responder2
Overcommit está habilitado por padrão no Linux no modo heurístico. Isso significa que o kernel geralmente permitirá overcommit - o que significa que prometerá mais memória para todos os processos que o solicitarem do que realmente pode entregar, na esperança de que os processos nunca comecem a usar toda a memória ao mesmo tempo. Talvez o overcommit esteja desabilitado em seu servidor, você pode verificar executando:
$ cat /proc/sys/vm/overcommit_memory
Se o valor for 0, a supercomprometimento heurístico será ativada.
Se ocorrer uma situação em que o uso real da memória aumenta além da quantidade de RAM que o sistema pode fornecer, o kernel ativará o OOM killer, que tentará eliminar processos para liberar memória. Geralmente mata os processos mais jovens que consomem grandes quantidades de RAM, mas você não pode depender disso. Isso pode (e irá) causar estragos. Você pode modificar a afinidade do OOM para eliminar processos específicos ajustando /proc//oom_adj (por exemplo, se quiser evitar uma situação em que o OOM elimine o banco de dados ou algum outro usuário [ab] de RAM grande).
Portanto, se o seu sistema entrar na fase OOM, as consequências para os processos Java podem ser que eles sejam eliminados instantaneamente - o que não geraria mensagens de 'Sem memória' nos logs Java que você está observando.
Definir Xmx e Xms com o mesmo valor impedirá o redimensionamento do heap, mas isso não significa que o processo Java começará a usar toda a memória de uma vez na inicialização. Ele alocará a quantidade necessária de memória VIRT, mas o conjunto de dados residentes não crescerá até Xms, mas permanecerá tão baixo quanto necessário.
Em termos de memória virtual: o kernel irá prometer (comprometer-se demais) ao processo Java tanto quanto solicitar (Xmx + algum adicional), mas toda essa memória não será alocada imediatamente. A quantidade necessária para os dados atuais será alocada apenas, e você pode ver quanto observando o tamanho do conjunto residente (memória física não trocada que uma tarefa usou). Para ver os tamanhos VIRT e RSS você pode executar o seguinte comando:
$ ps aux | egrep '(^USER|java)'
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
tomcat 10229 21.5 9.1 6813688 548344 ? Sl 09:01 1:10 ....java...
Com toda probabilidade, os erros que você está observando são uma indicação de que o programa em execução no processo da máquina virtual Java não possui espaço de heap. Tente aumentar a configuração Xmx e teste novamente seu aplicativo.