Skip to content

Java and Memory Management

Java Performance Optimization

Java on Kubernetes. Java Memory Arguments for Containers

Benchmarking modern Java Virtual Machines and the next-generation garbage collectors

  • jet-start.sh: Performance of Modern Java on Data-Heavy Workloads, Part 1 馃専 The Java runtime has been evolving more rapidly in recent years and, after 15 years, we finally got a new default garbage collector: the G1. Two more GCs are on their way to production and are available as experimental features: Oracle’s ZGC and OpenJDK’s Shenandoah. We at Hazelcast thought it was time to put all these new options to the test and find which choices work well with workloads typical for our distributed stream processing engine, Hazelcast Jet.

Relevant JVM Metrics

Metric Details / Reference
GC Throughput Repeated Full GC happens way before OutOfMemoryError
ref1
ref2
etc

Common JVM Errors

JVM Error Details / Reference
OutOfMemoryError Repeated Full GC happens way before OutOfMemoryError
ref1
ref2
StackOverflowError ref
etc

Tuning Jenkins GC

Tuning Java Containers

Debugging java applications on OpenShift and Kubernetes

List of Performance Analysis Tools

Threadumps, Heapdumps and GC Analysis Tools

Garbage Collection and Heap Offloading

Java Tracing Tools. JDK Flight Recorder

Cambios importantes en la gesti贸n de memoria de Java 8 de Oracle (2014)

PermGen no pertenece al heap y los objetos no son promocionados a esta secci贸n de memoria gestionada durante un GC. Como bien dices es un espacio contiguo al heap, pero tambi茅n se limpia cada vez que la tenured/old generation procede a un GC. No es una generaci贸n separada del mismo modo que es la young generation, y no hay un mecanismo espec铆fico para un GC separado de PermGen. La tenured/old generation y la permanent generation proceden a un GC cuando una de las dos se llena.

De todos modos no me queda claro si incorporaron PermGen dentro del heap en Java 7, aunque poco importa ya con los cambios en Java 8.

Mejor empiezo por introducir qu茅 implementaci贸n de JVM es Java 8 de Oracle. Existen numerosas implementaciones de JVM y cada una utiliza diferentes soluciones para la gesti贸n de memoria.

Dos de las soluciones m谩s conocidas y populares de JVM han sido HotSpot de Sun (habitual en Tomcat) y JRockit de BEA (Weblogic). Ambas compa帽ias fueron compradas por Oracle y Java 8 viene a ser la integraci贸n definitiva de ambas soluciones.

Hist贸ricamente se consideraba que HotSpot es el JVM con mejor rendimiento de las dos, si bien JRockit es valorada como la m谩s escalable.

Originalmente en HotSpot no hab铆a generaci贸n permanente. Objetos y clases de JVM se almacenaban juntas. Las clases de 茅sta JVM eran est谩ticas y pr谩cticamente no se utilizaban ‘Class Loaders’ (Load y Unload/Collection de Clases). PermGen surgi贸 como una mejora de rendimiento. Por defecto los datos en la generaci贸n permanente no se eliminan nunca (son datos de JVM y no de aplicaci贸n, pudiendo variar seg煤n la p贸l铆tica de garbage collection). Esto pod铆a llenar la generaci贸n permanente generando un OutOfMemoryErrors si se produc铆a un elevado n煤mero de classloading. En muchos casos un problema con una generaci贸n permanente implica reiniciar regularmente la JVM y la aplicaci贸n Java.

Actualmente las clases de JVM son din谩micas y el espacio requerido para metadatos puede cambiar f谩cilmente.

A diferencia de HotSpot VM, JRockit carece de generaci贸n permanente y en cambio almacena los metadatos ‘off the heap’ en memoria nativa. Estos buffers de c贸digo son liberados constantemente cuando sus ClassLoaders no se utilizan. El problema de OutOfMemory en JRockit no es diferente a HotSpot, excepto por el hecho de ser memoria nativa en lugar de memoria heap. Hay dos diferencias significativas. Primero, en JRockit la limpieza de metadatos est谩 habilitada siempre por defecto y segundo, no hay tama帽o l铆mite fijo para el espacio de metadatos. Uno de los principales problemas con HotSpot es su dificultad para seleccionar un tama帽o adecuado para la generaci贸n permanente. 驴128MB, 256MB? Es muy dif铆cil acertar para cada aplicaci贸n. JRockit es din谩mico en la gesti贸n de memoria reservada para metadatos y sin l铆mites de tama帽o (a excepci贸n de la memoria del sistema). JRockit es tambi茅n el 煤nico JVM con soporte de heaps no contiguos (uso de memoria por encima y por debajo del alojamiento del kernel y otras librer铆as), importante en el caso de Windows donde su kernel a menudo se ubica en mitad del espacio de direcciones.

Java 8 (HotRockit?) incorpora todas las herramientas de monitorizaci贸n de HotSpot (Java VisualVM, jstat, jmap) y JRockit (Java Mission Control, Java Flight Recorder). Muy interesante.

Un inconveniente de Java 8 es la fragmentaci贸n de la memoria nativa para metadatos, pero probablemente incluya compactaci贸n en un futuro pr贸ximo.

En el 2016 saldr谩 Java 9 con la funcionalidad de auto-tuning y soporte de tama帽os Heap multi-gigas.

En cualquier caso hay una tendencia al Heap-Offloading. El consumo de memoria en Java tiene un coste y las pausas/latencias causadas por los Full GC son proporcionales al tama帽o del heap. Estas pausas son notables en tama帽os de heap > 1Gb, con un considerable impacto en aplicaciones de tiempo real donde un proceso que no responde r谩pido puede ser descartado del cluster. A煤n as铆, los servidores actuales hacen uso de frameworks muy pesados y f谩cilmente requieren heaps > 4Gb. Una soluci贸n a este problema es alojar fuera del heap los objetos poco utilizados mediante t茅cnicas de serializaci贸n/deserializaci贸n (cach茅). El heap de memoria se mantiene peque帽o y el Full GC se completa en milisegundos. Ejemplos:

  1. cach茅 de sesi贸n de usuarios, donde un fichero mapeado en memoria almacena gigabytes de sesiones de usuarios inactivos. Una vez que el usuario hace log-in, la aplicaci贸n dispone de todos sus datos sin ser necesaria una consulta a la BBDD.
  2. cach茅 de resultados computacionales como queries, p谩ginas html, etc (donde el coste computacional es mayor a la deserializaci贸n)