JDK 27 va más rápido de lo que cuentan sus JEPs
Más de 2.300 commits desde JDK 26 y mejoras que no salen en la lista de JEPs: HashMap.putAll, URLs, AES y un arreglo para pausas de G1 de más de 90 segundos. Repasamos el informe de rendimiento de Inside Java.
Actualizar a JDK 27 te da rendimiento aunque no cambies una línea de código. Inside Java ha publicado el repaso de rendimiento de esta versión, y la lista va mucho más allá de los nueve JEPs: más de 2.300 commits desde JDK 26 en librerías, recolectores, JIT y runtime.
Los dos cambios gordos ya los contamos en el artículo de JDK 27: G1 por defecto en todas partes (JEP 523) y las cabeceras compactas activadas por defecto (JEP 534). Aquí va la letra pequeña, que es donde está lo interesante.
Cabeceras compactas, ahora con números
En una configuración típica de HotSpot de 64 bits, cada cabecera de objeto pasa de 12 a 8 bytes. Las mediciones que cita el artículo:
- 22 % menos de heap y 8 % menos de CPU en una configuración de SPECjbb2015.
- 15 % menos recolecciones, tanto con G1 como con Parallel GC, en otra configuración.
- Alrededor de un 10 % menos de tiempo en un benchmark de un parser JSON muy paralelo.
Si algo se te tuerce, se desactivan con -XX:-UseCompactObjectHeaders.
Código que ya tienes y que ahora va más rápido
HashMap.putAll() y el constructor HashMap(Map) tienen caminos rápidos especializados (JDK-8371656). En AWS Graviton, con las llamadas expuestas a cinco tipos de Map, el tiempo por operación bajó entre un 61 % (un HashMap de cinco entradas) y un 86 % (un HashMap no modificable de 150 entradas).
O sea, que este patrón de toda la vida se aprovecha sin que toques nada:
static Map<String, Integer> merge(Map<String, Integer> defaults,
Map<String, Integer> overrides) {
// Copia y mezcla: los dos caminos que JDK 27 acelera
Map<String, Integer> config = new HashMap<>(defaults);
config.putAll(overrides);
return config;
}Más ejemplos del mismo estilo:
- Abrir ficheros: se elimina una llamada
fstatredundante (JDK-8373647). En un benchmark de estrés, de unos 3.722 a 3.192 ns/op, un 14 % menos. - Formatear URLs: al menos un 60 % menos de tiempo, según qué componentes lleve la URL (JDK-8379557).
AttributedString: iterar con atributos tarda entre un 35 % y un 40 % menos (JDK-8380794).- AES/ECB en x86: de unos 11,52 a 8,38 µs/op en un Intel Core i9-14900HX, que el artículo traduce en un 37 % más de throughput (JDK-8376164).
El arreglo que alguno va a agradecer
Hay usuarios que reportaron pausas de G1 de más de 90 segundos cuando los conjuntos de code roots por región se volvían caros de recorrer y de hacer crecer. JDK-8358342 corrige ese mal escalado.
Si alguna vez has visto una pausa así sin explicación, este es el bug que tienes que leer.
Aviso si usas Lazy Constants
Lazy Constants (JEP 531) sigue en preview en JDK 27, en su tercera ronda, y su API cambia: se eliminan isInitialized() y orElse(), porque su uso podía saltarse el modelo de inicialización previsto, y se añade Set.ofLazy(...) junto a las factorías de listas y mapas perezosos que ya existían. Si la probaste en JDK 26 con --enable-preview y llamabas a esos métodos, tu código no compilará en JDK 27.
Una regresión cazada por el camino
El Object Monitor Table, que guarda fuera de la cabecera del objeto la relación entre objetos y monitores inflados, ahora está activado por defecto. Al activarlo apareció una regresión del 30 % en un benchmark con mucha sincronización. Se resolvió reduciendo los intentos de spin antes de inflar un monitor con contención (JDK-8382311).
El artículo cierra diciendo que JDK 28 ya tiene su propia tanda de mejoras integradas o en desarrollo, que contarán en la primavera de 2027.