Para aplicaciones en contenedores, es difícil identificar problemas causados por el uso excesivo de memoria. En caso de que el uso supere el límite de memoria del contenedor, una aplicación puede fallar silenciosamente sin dejar rastro alguno.
En este artículo, repasaré algunas de las técnicas que se pueden utilizar para identificar la fuente del consumo de memoria en una aplicación de contenedor Java.
Tipo de Memoria
En una aplicación Java típica, la memoria se puede dividir en gran medida en heap y no heap. La memoria heap se puede establecer proporcionando los parámetros de JVM pertinentes al iniciar cualquier aplicación Java.
La memoria no heap consiste en memoria nativa utilizada por el JVM en sí o por cualquier biblioteca utilizada dentro de la aplicación mediante JNI (Java Native Interface).
Método
Para la memoria heap, se puede tomar un volcado de heap y analizarlo utilizando herramientas de análisis de volcado de heap. Una de las mejores herramientas para el análisis de volcado de heap es eclipse MAT.
Java proporciona un mecanismo para rastrear la asignación de memoria nativa al habilitar seguimiento de memoria nativa, pero puede no revelar toda la memoria asignada por bibliotecas nativas.
Jemalloc es una utilidad que se puede utilizar para rastrear la memoria asignada por bibliotecas nativas. La memoria nativa se asigna utilizando un administrador de memoria predeterminado llamado malloc. Jemalloc es una implementación general de malloc con la que se puede habilitar el seguimiento de la asignación de memoria. Rastrea toda la asignación de memoria nativa y genera volcados de perfil de heap.
Estos perfiles de heap luego pueden ser analizados utilizando la utilidad Jeprof. Jeprof genera el informe de asignación de heap, resaltando la memoria utilizada por funciones en la aplicación.
Análisis
A continuación se presenta un análisis de memoria de una aplicación de contenedor de Java de muestra. La aplicación carga un modelo de muestra Tensorflow para permitir la utilización de memoria nativa y se ejecuta en un contenedor Docker.
A continuación se muestra el consumo de memoria de Docker. Muestra 254MB. Intentemos identificar la fuente del consumo de memoria.
Memoria Total
Para tener una idea de la memoria total utilizada por el proceso de la aplicación, podemos verificar el Tamaño del Conjunto Residente (RSS). Es la memoria comprometida total que reside en la memoria principal o RAM. Existen múltiples utilidades que pueden ayudar a verificar esto, como top, ps o pmap.
Comprobar RSS no ayuda a identificar la fuente raíz del consumo. Para la aplicación de ejemplo, utilizando el siguiente comando, el RSS total es de 376MB.
ps --no-header -o rss $(pidof java)
Análisis de Heap
A continuación se muestra el consumo de memoria heap generado por la herramienta eclipse MAT. La memoria retenida total se muestra como 2.2MB, lo cual está muy por debajo del consumo total de memoria mostrado por Docker e indica que la mayoría del consumo proviene del área no heap.
Análisis de Memoria Nativa
Al revisar el resumen de memoria nativa utilizando el comando a continuación, el uso total de memoria parece ser aproximadamente 99MB. Sin embargo, este valor es menor que el consumo total de memoria y no identifica con precisión la causa raíz del problema.
jcmd $(pidof java) VM.native_memory \
| grep -P "Total.*committed=" \
| grep -o -P "(?<=committed=)[0-9]+(?=KB)"
Análisis de Memoria Off-Heap
Un análisis utilizando Jemalloc y Jeprof revela que el uso de memoria nativa se atribuye principalmente a la biblioteca Tensorflow, con un consumo total de aproximadamente 112MB.
Esta información proporciona una clara indicación de la fuente del uso de memoria nativa y puede ser investigada más a fondo para minimizar cualquier consumo excesivo.
Conclusión
El análisis de memoria Java es crítico, especialmente para aplicaciones basadas en contenedores. Conocer la fuente del consumo de memoria en una aplicación puede ayudarnos a entender el requisito de memoria y reducir los costos de la aplicación eliminando el consumo innecesario.
Al verificar el consumo de memoria, es necesario identificar todos los tipos de memoria y sus fuentes. El análisis de volcado de heap puede identificar las fuentes de consumo de memoria heap, y Jemalloc y Jeprof son útiles para identificar las fuentes de consumo de memoria nativa.
Enlace de Código de Aplicación de Ejemplo
Source:
https://dzone.com/articles/java-container-application-memory-analysis