Command Palette

Search for a command to run...

ES·EN

Nivel 2 · 20 min

Memoria JVM

Entender cómo la JVM gestiona la memoria es esencial para diagnosticar OutOfMemoryErrors, ajustar el rendimiento del GC y diseñar sistemas que manejen millones de objetos eficientemente.

Áreas de memoria de la JVM

La memoria de la JVM se divide en: Heap (generaciones Young + Old para asignación de objetos), Stack (por hilo, almacena frames con variables locales), Metaspace (metadata de clases, bytecode de métodos, desde Java 8 reemplaza PermGen — crece dinámicamente, acotado por -XX:MaxMetaspaceSize), Code Cache (código nativo compilado por JIT), y áreas off-heap como Direct Buffers. Cada región tiene modos de falla distintos: heap → OutOfMemoryError: Java heap space, metaspace → OutOfMemoryError: Metaspace.

Generaciones Young y Old, TLAB

La generación Young (Eden + dos espacios Survivor S0/S1) es donde se asignan todos los nuevos objetos. Eden se particiona en Thread-Local Allocation Buffers (TLABs) — cada hilo obtiene un chunk privado de Eden, permitiendo asignación sin sincronización. Los objetos que sobreviven un número configurable de GC menores (-XX:MaxTenuringThreshold, por defecto 15) se promueven a la generación Old. Un GC menor colecta solo Young; un GC mayor/full colecta todo.

Carga de clases

La JVM carga clases de forma lazy en el primer uso a través de la jerarquía de class loaders: Bootstrap → Extension/Platform → Application. Cada class loader mantiene su propio namespace — dos clases cargadas por loaders diferentes son distintas aunque sean idénticas. La carga de clases es la fuente de ClassCastException entre boundaries de loaders y de leaks de metaspace en entornos dinámicos.

Puntos clave

  • Los nuevos objetos van a Eden (generación Young). TLAB hace que la asignación sea casi gratuita — solo un incremento de puntero por hilo.
  • El GC menor se dispara cuando Eden se llena. Solo se colecta la generación Young — típicamente pausas '<' 50ms para heaps bien ajustados.
  • Metaspace crece sin límite a menos que se acote con -XX:MaxMetaspaceSize. La carga dinámica de clases puede agotarlo.

Code example

// Verificar regiones de memoria JVM en runtime
Runtime rt = Runtime.getRuntime();
long heapUsed = rt.totalMemory() - rt.freeMemory();
long heapMax = rt.maxMemory();

// Flags JVM clave para ajuste de memoria
// -Xms512m -Xmx2g          # heap inicial y máximo
// -XX:NewRatio=2            # Old:Young = 2:1
// -XX:MaxMetaspaceSize=256m # acotar metaspace
// -XX:+PrintGCDetails       # log GC detallado (Java 8)
// -Xlog:gc*                 # logging unificado (Java 9+)