Pasar al contenido principal
Busca optimizar la representación de objetos en la JVM con JEP 401, una propuesta que promete mejoras de rendimiento y que se está probando en builds early-access antes de su llegada prevista a JDK 28.
14/08/2026
abstracto

Project Valhalla es la propuesta de OpenJDK para repensar cómo la JVM representa los objetos. Doce años después de arrancar, su pieza central —JEP 401, "Value Classes and Objects"— ya circula como funcionalidad preview en builds early-access, antes de su llegada planeada a JDK 28 en marzo de 2027. Se buscó ir más allá de la teoría y comprobarlo de forma práctica, con un build early-access de JDK 27 (27-jep401ea3), para ver qué tan reales son las promesas de rendimiento de las que tanto se habla.

¿Qué es Project Valhalla y por qué importa? 

Project Valhalla arrancó en 2014 como un proyecto de investigación dentro de OpenJDK, con un objetivo ambicioso: eliminar uno de los costos estructurales más antiguos de la JVM, el hecho de que todo objeto —por pequeño que sea— cargue con una identidad y viva detrás de un puntero. JEP 401 es la propuesta que finalmente aterriza esa idea en forma concreta, y ya está confirmada para su integración en la rama principal de OpenJDK. Para equipos que operan servicios backend sobre la JVM, especialmente aquellos con alta densidad de objetos pequeños y de vida corta, representa una de las optimizaciones de rendimiento más significativas en mucho tiempo.

El recorrido hasta llegar aquí ha sido largo, y todavía no termina:

  • 2014 — arranca Project Valhalla como proyecto de investigación.
  • 2022 — se publica JEP 401 (Value Classes and Objects).
  • 2025-2026 — llegan los primeros builds early-access con soporte de JEP 401 para pruebas públicas; el que se utiliza en esta demo es uno de ellos.
  • JDK 27 (septiembre 2026) — sale sin Valhalla; sigue disponible solo en builds early-access como el utilizado en esta prueba.
  • JDK 28 (marzo 2027) — JEP 401 llega como funcionalidad preview en una versión oficial.
  • JDK 29 (probable LTS, septiembre 2027) — el arquitecto de Java Brian Goetz ya ha advertido que esperar que JEP 401 salga de preview para esa versión sería "optimista".

Esa última advertencia importa para cualquier equipo que esté evaluando esto: incluso después de convertirse en preview oficial, es razonable planificar una fase de evaluación prolongada —del orden de 12 a 18 meses— antes de pensar en llevar value classes a producción crítica.

JEP 401 es, además, solo el primer escalón. Detrás vienen dos piezas que dependen de él: los genéricos especializados, que permitirían representar algo como List<int> o List<Point> de forma nativa en vez de forzar boxing/unboxing sobre cada elemento; y los tipos no anulables (non-nullable types), que le permiten a la JVM garantizar en tiempo de compilación que un valor nunca será null, lo que a su vez habilita optimizaciones todavía más agresivas de representación. Ambas quedan para fases posteriores del proyecto; por ahora, JEP 401 se concentra en sentar la base: las value classes.

¿Qué son las value classes?

Una value class es un tipo cuyas instancias no tienen identidad de objeto: dos instancias con los mismos datos son indistinguibles entre sí, algo que se puede comprobar en código con el nuevo método Objects.hasIdentity(Object). Esto le da a la JVM libertad para representarlas de forma mucho más compacta que un objeto tradicional. En concreto, el modelo habilita tres optimizaciones:

  • Menor huella de memoria: al no necesitar identidad, la JVM puede prescindir del header de objeto y guardar los valores de forma más densa.
  • Aplanado en arrays (heap flattening): los elementos se guardan contiguos en memoria, como un array de structs, en vez de un array de punteros a objetos sueltos por ahí en el heap.
  • Scalarización (scalarization): cuando una value class no "escapa" de un método, el JIT puede evitar reservarla en el heap del todo y mantenerla en registros.

En modo preview, el propio JDK migra algunas clases muy usadas —Integer, LocalDate, entre otras— para que se comporten como value classes. Los desarrolladores también pueden declarar las suyas propias con la palabra clave value class, pensadas para tipos de dominio que representan datos puros: coordenadas, montos de dinero, timestamps, IDs compuestos. Eso sí: la mejora no es automática en todo el código. Según la propia documentación del proyecto, el beneficio se concentra especialmente en:

Estructuras de datos densas y colecciones grandes.

  • Arrays recorridos de forma secuencial.
  • Cómputo intensivo sobre tipos de datos puros (coordenadas, fechas, montos).
  • Servicios con alto volumen de instancias pequeñas y de vida corta: procesamiento de pagos, pipelines de eventos, sistemas de trading, analítica en tiempo real.

Para lógica de negocio tradicional, con pocas instancias y sin ese patrón de alta densidad, el impacto
esperado es marginal.

La demo: ValhallaBenchmark, un banco de pruebas para las value classesdel JDK

Para que la comparación fuera justa se escribieron a mano dos clases con identidad tradicional que tienen exactamente los mismos campos que sus contrapartes del JDK, para aislar el efecto de la identidad y nada más que eso:

  • BoxedInt, equivalente a Integer: un solo campo int.
  • Ymd, equivalente a LocalDate: tres campos int (año, mes, día).

La demo, ValhallaBenchmark.java, hace tres cosas por cada par de clases:

  1. Imprime Objects.hasIdentity(...) sobre una instancia de cada tipo, para dejar en negro sobre blanco
    quién tiene identidad y quién no.
  2. Mide memoria y tiempo al construir un array grande (5 millones de elementos para Integer, 2,5
    millones para LocalDate, que pesa más).
  3. Mide el throughput de recorrer el array y sumar sus valores, con calentamiento previo (warmup)
    para dejar que el JIT optimice antes de cronometrar.

Cómo ejecutarlo

El build early-access utilizado (27-jep401ea3+1-1) proviene de la distribución oficial del equipo de Project Valhalla, publicada en jdk.java.net/valhalla. Es el mismo canal en el que Oracle libera, de forma periódica, nuevas compilaciones de prueba de JEP 401 sobre una base incompleta de la próxima versión del JDK — en este caso, JDK 27. Basta con descargar el paquete correspondiente al sistema operativo, descomprimirlo en cualquier carpeta y apuntar la variable JDK del script hacia esa ruta: no requiere instalación ni sustituye al JDK de producción.

Los dos archivos de la demo (ValhallaBenchmark.java y run_benchmark.bat) se encuentran en la misma carpeta. Antes de ejecutar:

  1. Revisar que la variable JDK dentro de run_benchmark.bat apunte a la instalación del build earlyaccess (por defecto C:\jdk-27).
  2. Ejecutar .\run_benchmark.bat desde PowerShell o cmd en esa carpeta.

El script compila y ejecuta con los flags de preview necesarios:
 

Imagen
código

Los parámetros --n, --warmup e --iters son ajustables al inicio del propio .bat si se quiere repetir la prueba con otros tamaños.

El script también deja un registro de la actividad del recolector de basura en out\gc-benchmark.log, gracias al flag-  Xlog:gc*:file=...:time,uptime,level,tags que incluye run_benchmark.bat. Cada línea recoge el instante del evento (time y uptime), el nivel de detalle (level) y la categoría del propio recolector (tags, como [gc] o [gc,heap]). Sirve, sobre todo, para verificar desde fuera que las mediciones de memoria de la demo son fiables

Resultados

Con este cambio de enfoque, los números sí muestran las ganancias que se esperan de Valhalla, de
forma clara y reproducible entre ejecuciones:

Imagen
TABLA EXPLICATIVA 1
Imagen
TABLA EXPLICATIVA 2

 

Un detalle que vale la pena señalar: construir los arrays fue más lento para las value classes que para las clases identidad (Integer: 48 ms vs BoxedInt: 24 ms; LocalDate: 51 ms vs Ymd: 44 ms). Tiene sentido — la construcción se midió una sola vez, sin calentamiento previo, mientras que la suma se midió tras 10 iteraciones de warmup que le dan tiempo al JIT para aprovechar el flattening. El patrón es consistente: las value classes cuestan un poco más construirlas la primera vez, pero una vez en el array, ocupan menos memoria y se recorren notablemente más rápido.

Conclusiones

  • Las ganancias de Valhalla son reales, pero no automáticas: dependen de que la clase concreta tenga ya soporte maduro de flattening en el build que se esté usando. Con Integer y LocalDate —las value classes que Oracle migró y afinó— se observó hasta 2,5x menos memoria y 2,4x más throughput en iteración.
  • Recomendación práctica: no asumir ganancias por el simple hecho de declarar value class. Conviene benchmarkear con la carga propia, en el build propio, antes de planear cualquier migración — igual que se recomienda para cualquier otra optimización de bajo nivel.
  • Sigue siendo una funcionalidad preview. Aterrizara en JDK 28 y, según ha señalado el arquitecto de Java Brian Goetz, es probable que continúe en preview incluso en JDK 29 (LTS). Todavía no es el momento de llevarlo a producción crítica sino el de experimentar y familiarizarse.

 

 

Imagen
Patricio Flores

Patricio Flores
Técnico de Software
ALTIA