
Uno de nuestros sistemas SAP (pila PI ABAP+JAVA) estaba dando problemas de rendimiento. Los 64 GB completos configurados para la máquina se acaparan (y también los 8 núcleos). Todo el mundo sospecha de la parte de Java, pero yo pienso diferente.
Los nodos del servidor Java se reiniciaron con un error de falta de memoria. Al observar los archivos hprof, descubrí que tenían solo 1,2 G (promedio de 3 nodos de servidor) de tamaño, cuando se configuran 3 GB (tanto -Xms como Xmx) de montón para los nodos del servidor. Esta observación lleva a la siguiente duda.
He leído que cuando Xms y Xmx se configuran con el mismo valor, a la jvm se le asigna todo el montón cuando se inicia. Si es el caso, los nodos del servidor tendrían 3 GB de almacenamiento dinámico desde el principio. Si es así, ¿por qué no se refleja en el archivo hprof o si hprof contiene solo la memoria asignada a los objetos durante el tiempo de ejecución, el tamaño indica claramente que la memoria del montón estaba libre (más del 50%), entonces, cómo se produce el error OOM? ..!!..??
También sé que Linux hace algo llamado sobrecompromiso de memoria. es decir, la memoria en realidad no se proporciona cuando se solicita sino cuando realmente se utiliza. ¿Esto contribuye a la excepción de falta de memoria? Por ejemplo, cuando la JVM inicia, el sistema operativo le dice que se le han asignado 3 GB de memoria, pero en realidad lo pospone hasta que realmente sea necesario. Para cuando la jvm realmente intenta asignar la memoria a los objetos, es posible que otras aplicaciones hayan agotado la memoria. Es posible...??
Incluso si los nodos de Java tuvieran un problema de pérdida de memoria, ¿no se limitaría a los 3 GB de montón? ¿Cómo puede acaparar los 64G completos de memoria física...?
Una cosa más que observé fue que el espacio de intercambio solo se utilizaba en un 50%.
¡Alguna luz sobre esto...!
Respuesta1
SAP OSS también estaba investigando el asunto. Hoy recibí la respuesta de ellos. Mi observación fue correcta. Java no fue el culpable. La pila ABAP enfrentaba algún problema y no liberaba memoria. Después de reiniciar el proceso de trabajo ABAP, se liberó memoria a nivel del sistema operativo.
Pero también me gustaría entender la parte resaltada de la pregunta, como si tal situación puede ocurrir o no, dando como resultado errores de JAVA OOM...??..!!. Cualquier información al respecto será de gran ayuda.
Respuesta2
La sobrecompromiso está habilitada de forma predeterminada en Linux en modo heurístico. Eso significa que el kernel generalmente permitirá un compromiso excesivo, lo que significa que prometerá más memoria a todos los procesos que la soliciten de la que realmente puede entregar, con la esperanza de que los procesos nunca comiencen a usar toda la memoria al mismo tiempo. Tal vez el overcommit esté deshabilitado en su servidor, puede verificarlo ejecutando:
$ cat /proc/sys/vm/overcommit_memory
Si el valor es 0, se activa la sobreasignación heurística.
Si ocurre una situación en la que el uso real de la memoria crece por encima de la cantidad de RAM que el sistema puede proporcionar, el kernel activará OOM Killer, que intentará finalizar los procesos para liberar memoria. Por lo general, eliminará los procesos más jóvenes que consumen grandes cantidades de RAM, pero no puedes depender de ello. Puede (y causará) estragos. Puede modificar la afinidad de OOM para eliminar procesos específicos ajustando /proc//oom_adj (por ejemplo, si desea evitar una situación en la que OOM elimine la base de datos o algún otro usuario de RAM [ab] de gran tamaño).
Por lo tanto, si su sistema entra en la fase OOM, las consecuencias para los procesos Java podrían ser que se eliminen instantáneamente, lo que no generaría mensajes de "Memoria insuficiente" en los registros de Java que está observando.
Establecer Xmx y Xms en el mismo valor evitará el cambio de tamaño del montón, pero eso no significa que el proceso Java comenzará a usar toda la memoria a la vez al inicio. Asignará tanta memoria VIRT como necesite, pero el conjunto de datos residentes no crecerá hasta Xms, sino que permanecerá tan bajo como sea necesario.
En términos de memoria virtual: el kernel prometerá (sobrecomprometerá) al proceso Java tanto como solicite (Xmx + algo adicional), pero toda esa memoria no se asignará de inmediato. La cantidad necesaria para los datos actuales se asignará únicamente y podrá ver cuánto observando el tamaño del conjunto residente (memoria física no intercambiada que ha utilizado una tarea). Para ver los tamaños VIRT y RSS, puede ejecutar el siguiente 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...
Con toda probabilidad, los errores que está observando son una indicación de que el programa que se ejecuta en el proceso de la máquina virtual Java carece de espacio en el montón. Pruebe aumentando la configuración Xmx y vuelva a probar su aplicación.