Monitorización de procesos java: Prevenir OutOfMemoryError

Hola compañeros de la shell,

En esta entrada vamos a centrarnos en la revisión de procesos java, más concretamente en la revisión del consumo de memoria heap de la JVM con el objetivo de tratar de prevenir el clásico error OutOfMemoryError.

Antes de nada, sería recomendable refrescar cómo funciona la memoria de la JVM. Una buena introducción en castellano al tema sería:

Garbage Collector – Adictos al trabajo

Una vez familiarizados con el tema, existen dos preguntas realmente útiles para enfrentarnos a este tipo de problemas:

1. ¿Cómo comprobar el máximo de memoria heap de un proceso java en ejecución?

2. ¿Cómo medir la memoria heap consumida por un proceso java en ejecución?

Para medir estos dos parámetros utilizaremos el comando jstat.

Por otro lado, la respuesta directa a estas dos preguntas la encontramos, como tantas otras veces, en stackoverflow:

https://stackoverflow.com/questions/43735962/how-to-get-heap-usage-using-jstat

Por lo que, ejecutando un sencillo script como el que detallamos a continuación podemos obtener el valor máximo de memoria heap así como la memoria heap consumida de un PID que pasemos por parámetro:

#!/bin/sh
# Ver https://stackoverflow.com/questions/43735962/how-to-get-heap-usage-using-jstat

JSTAT_GC="${JAVAHOME}/bin/jstat -gc"
JSTAT_GCCAPACITY="${JAVAHOME}/bin/jstat -gccapacity"

USED_HEAP_MEM=`$JSTAT_GC $1 | tail -1 | awk '{print sum=($3+$4+$6+$8)/1024}'`
MAX_HEAP_MEM=`$JSTAT_GCCAPACITY $1 | tail -1 | awk '{print sum=($2+$8)/1024}'`

echo "PID=$1;MAX_HEAP_MEM=$MAX_HEAP_MEM;USED_HEAP_MEM=$USED_HEAP_MEM"

Otra posibilidad alternativa, aunque menos recomendable (ya que «para» durante una pequeña fracción de tiempo la JVM) sería usar el comando jmap:

jmap -heap PID

** Actualización 24-04-2025:

En Red Hat Enterprise Linux release 8.10 (Ootpa) y con java version «17.0.13» usamos el comando:

jinfo -flags PID

El campo que muestra el Xmx es el -XX:MaxHeapSize

Ejemplo:

jinfo -flags 363465
VM Flags:
-XX:CICompilerCount=15 -XX:CompressedClassSpaceSize=436207616 -XX:ConcGCThreads=3 -XX:G1ConcRefinementThreads=12 -XX:G1EagerReclaimRemSetThreshold=256 -XX:G1HeapRegionSize=33554432 -XX:GCDrainStackTargetSize=64 -XX:InitialHeapSize=33554432 -XX:MarkStackSize=4194304 –XX:MaxHeapSize=107374182400 -XX:MaxMetaspaceSize=536870912 -XX:MaxNewSize=64424509440 -XX:MinHeapDeltaBytes=33554432 -XX:MinHeapSize=33554432 -XX:NonNMethodCodeHeapSize=8192380 -XX:NonProfiledCodeHeapSize=121732930 -XX:ParallelGCThreads=12 -XX:ProfiledCodeHeapSize=121732930 -XX:-RequireSharedSpaces -XX:ReservedCodeCacheSize=251658240 -XX:+SegmentedCodeCache -XX:SoftMaxHeapSize=107374182400 -XX:+UseCompressedClassPointers -XX:+UseFastUnorderedTimeStamps -XX:+UseG1GC -XX:-UseSharedSpaces

P.D.: Agradecimiento especial a Juanma Palafox por arrojar luz enseñándonos jmap y jstat.

Espero que os sirva.

Nos vemos al otro lado de la pantalla negra.

Esta entrada fue publicada en Sin categoría. Guarda el enlace permanente.

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *