Este artículo es un anexo del artículo principal Java Dark Memory, para aportar detalle sobre este espacio concreto de memoria. En el artículo principal nos centramos en la observabilidad de espacios de memoria menos conocidos y más problemáticos.
Índice
1. ¿Qué es?
El Heap es la zona de memoria que almacena los objetos que se van creando en tiempo de ejecución y que es gestionada por el garbage collector.
El heap se divide en 3 areas principales:
Young Generation: es el destino inicial para los nuevos objetos. Cuando los objetos son usados en el código estos se situan en un subespacio dentro de este area que se llama Eden.
Cuando esta subzona se llena, hay un proceso de recolección menor que pasa objetos de esta zona a otra subsección llamada S0 dentro de la zona Survivor (dividida en S0 y S1). Los objetos que ya no estan referenciados serán desalojados por este mecanismo.Old Generation: esta zona podemos definirla como "el repositorio" de los objetos de larga duración. Básicamente aqui estarán los objetos que han pasado ya por varios ciclos de GC de la Young Generation.
Permanent Generation: en esta zona NO estarán almacenados los objetos procedentes de la old generation. Esta zona no funciona así.
Esta zona contiene metadatos de clases y metodos de la aplicación en tiempo de ejecución.
2. Observabilidad
- Con JMX y Mbeans, podemos ver el estado de cada unos de los espacios generacionales
- Con NMT podemos ver la memoria virtual y residente de todo el espacio
-
Con métricas prometheus: por ejemplo spring boot ofrece la siguiente métrica:
jvm_memory_<commited|used|max>_bytes{area="heap"}
- Con herramientas como Eclipse Memory Analyzer (MAT), podemos analizar en detalle todos los objetos alojados en los espacios generacionales y los motivos de su retención, para ello debemos gererar antes un HeapDump.
3. Límites
- Valor Start:
-Xms
- Valor Max:
-Xmx
4. Consideraciones
En microservicios ocupará entre un 15% y un 25%, en stateful “hay que medirlos”.
Un heap salubable, expuesto a larga duración, gráficamente ofrecerá un patrón de "sierra", lo que indica que los objetos pueden ser recolectados por el GC manteniendo el heap en niveles óptimos de ocupación
- Un heap no saludable, con patrón de escalera, es un idicador de memory leak. Los objetos se acumulan en la zona de tenured, y el GC no es capaz de recolectarlos. Se producirá una RuntimeException
java.lang.OutOfMemoryError: Java Heap Space
, cuando el GC no pueda desalojar y used=max.
- Podemos configurar el tipo y algoritmos de Garbage Collection, y es recomendable hacerlo. Si tenemos heap pequeños y CPU limita en un proceso, openjdk tomará decisiones (java ergonomics) sobre el GC y el heap. En muchas ocasiones esta decisión es utilizar el GC Parallel o pero aún, el Serial. Recomendamos siempre utilizar G1, aunque el heap sea pequeño. Aunque "gaste" un poco más de memoria en su propio espacio, a la larga es mucho más óptimo, y eficaz en la recolección de objetos relacionados con la memoria oscura y los direct buffers, que son el tema principal del artículo. Además G1 es capaz de realizar compactación del heap, reduciendo la fragmentación interna del espacio al mínimo (lo que también ahorra memoria residente).
Top comments (1)
¡Limpio y super claro!
¡Buen artículo Jose Antonio!