Project Valhalla: un decennio di evoluzione di Java punta a JDK 28
AI News

Project Valhalla: un decennio di evoluzione di Java punta a JDK 28

6 min
19/06/2026
JavaJVMOpenJDKPerformance

Un decennio di evoluzione di Java si avvicina alla conclusione

Il 15 giugno, l'ingegnere di Oracle Lois Foltan ha confermato una pietra miliare che molti nella comunità Java avevano iniziato a dubitare sarebbe mai arrivata. JEP 401: Value Classes and Objects è destinato all'integrazione nel repository principale di OpenJDK per JDK 28, previsto per il rilascio nel marzo 2027. Ciò segna la prima, attesa consegna di Project Valhalla, un'iniziativa lanciata nel 2014 per rimodellare fondamentalmente il modello di performance di Java.

L'integrazione è così significativa che ai committers è stato chiesto di sospendere i commit principali durante il processo. La richiesta di pull associata aggiunge oltre 197.000 righe di codice in 1.816 file. Tuttavia, come ha avvertito l'architetto del linguaggio Brian Goetz, questo è "solo la prima parte di Valhalla" e sarà una funzionalità di anteprima, disabilitata per impostazione predefinita.

Questo sviluppo conclude oltre un decennio di ricerca e cinque prototipi distinti. L'ambizione fondamentale del progetto è rimasta costante: consentire agli sviluppatori di scrivere classi che "codificano come una classe, ma funzionano come un int". L'obiettivo è quello di cancellare la storica dicotomia tra oggetti comodi e sicuri e primitive veloci e dense.

Il problema fondamentale: memoria "fluffy" vs. densa

Il modello di performance di Java è in conflitto con l'hardware moderno da anni. Dal 1995, con l'eccezione di otto tipi primitivi, tutto in Java è stato un tipo di riferimento. Una variabile come Point p è un puntatore, non i dati stessi.

Ciò porta a quella che Brian Goetz chiama una disposizione della memoria "fluffy". Un array di un milione di oggetti Point è un array di un milione di puntatori a un milione di oggetti individualmente allocati sparsi nell'heap. Ogni oggetto porta un'intestazione per i metadati e comporta costi di allocazione e garbage collection.

Le moderne CPU, tuttavia, prosperano sulla località di riferimento. I dati accessibili in sequenza e archiviati in modo contiguo nelle linee di cache (spesso 64 byte) funzionano ordini di grandezza più velocemente dei dati che richiedono l'indirizzamento dei puntatori e rischiano di perdere la cache. Valhalla mira a fornire una disposizione "densa", dove i campi degli oggetti siedono fianco a fianco in memoria.

Mentre l'analisi di escape può talvolta ottimizzare questo, è fragile e imprevedibile. Le value classes di Valhalla offrono un percorso prevedibile e dichiarativo per queste caratteristiche di performance.

Value Classes: l'anteprima di JDK 28

Quindi, cosa arriva esattamente in JDK 28? Gli sviluppatori acquisiscono la capacità di dichiarare una value class. Ciò appare come una classe normale ma viene con vincoli specifici: le sue istanze sono oggetti di valore senza identità.

Tutti i campi dell'istanza sono implicitamente finali, la classe è finale per impostazione predefinita e i metodi non possono essere sincronizzati. Il cambiamento più profondo è nell'operatore ==, che ora esegue un confronto di sostituibilità, controllando se due oggetti di valore sono della stessa classe con campi ricorsivamente uguali.

Una sfumatura critica, e un punto comune di confusione, è che nel modello JDK 28, una value class è ancora un tipo di riferimento. Gli oggetti di valore possono ancora essere null. La funzionalità che abilita i tipi non-null, JEP 8316779 "Null-Restricted Value Class Types", è una proposta separata e futura.

Meccanismi di performance: scalarizzazione e appiattimento

La JVM ottiene due potenti percorsi di ottimizzazione per gli oggetti di valore. La scalarizzazione consente al compilatore Just-In-Time (JIT) di scomporre un riferimento a un oggetto di valore nei suoi campi costituenti, eliminando effettivamente l'overhead di allocazione e garbage collection attraverso i confini dei metodi.

Più impattante per i carichi di lavoro intensivi di dati è l'appiattimento dell'heap. Qui, la JVM può codificare i dati di un oggetto di valore come un vettore di bit compatto e archiviarlo direttamente all'interno di un campo o elemento dell'array, eliminando il puntatore. Un Point[] può diventare un blocco contiguo di interi.

C'è un problema: i dati appiattiti devono essere leggibili e scrivibili in modo atomico per prevenire "tearing". Sull'hardware attuale, ciò spesso limita l'appiattimento a valori di 64 bit o meno (incluso un flag null). È qui che i futuri tipi con restrizioni di null diventano una leva di performance, potenzialmente consentendo a tipi più grandi di appiattirsi sacrificando l'atomicità.

continua a leggere sotto...

La lunga strada: evoluzione delle idee e della nomenclatura

Il percorso verso JDK 28 non è stato lineare. I primi prototipi hanno esplorato un modello "Q World", trattando i tipi di valore come completamente separati dagli oggetti. La svolta è arrivata con il prototipo "L World" intorno al 2019, che ha unificato i tipi di valore e i riferimenti agli oggetti sotto lo stesso tipo di carrier JVM.

La nomenclatura è evoluta in modo significativo. Termini come "tipi di valore", "classi inline" e "classi primitive" sono stati utilizzati e ritirati. Il modello "a due proiezioni" (ad esempio, Point.val e Point.ref) era potente ma mentalmente impegnativo per gli sviluppatori ed è stato infine semplificato.

Il modello attuale in JEP 401 è il risultato di questa rigorosa semplificazione. Come nota l'articolo, "dodici anni non sono stati dodici anni di 'scrivere codice'. Sono stati dodici anni di rifiutare idee, fino a quando non è rimasta quella che può effettivamente essere mantenuta".

La metà mancante: generics specializzati e il futuro

Mentre le value classes sono un enorme passo avanti, rimane un importante tetto di performance a causa dell'cancellazione del tipo di Java. In un List<Point>, il parametro di tipo T si cancella in Object, costringendo la JVM a materializzare gli oggetti di valore sull'heap.

Sbloccare collezioni generiche piatte e libere da allocazione richiede la seconda fase di Valhalla: generics specializzati. Ciò comporta sia Generics Universali (consentendo alle variabili di tipo di coprire i tipi di valore a livello di linguaggio) sia Generics Specializzati (generando layout ottimizzati e specifici per tipo a livello JVM).

Questo lavoro è ancora in corso e non fa parte di JDK 28. Il suo arrivo sarà cruciale per i framework e le librerie per sfruttare appieno il potenziale di Valhalla.

Impatto immediato e migrazione dell'ecosistema

L'effetto immediato nell'anteprima di JDK 28 include la migrazione delle proprie classi "basate su valori" di JDK. In particolare, le classi wrapper primitive (Integer, Long, ecc.) diventeranno value classes quando l'anteprima sarà abilitata.

Ciò significa che Integer[] inizierà ad avvicinarsi all'efficienza della memoria di int[], e l'overhead del boxing "si ridurrà drasticamente". Il JEP 402 associato, "Enhanced Primitive Boxing", ulteriormente smussa queste conversioni.

Per gli sviluppatori, il punto chiave da internalizzare è la distinzione tra identità e valore. Il codice che si basa sull'identità dell'oggetto (utilizzando == per il confronto dei riferimenti o blocchi synchronized) potrebbe richiedere un aggiustamento. Il nuovo helper Objects.requireIdentity() può imporre l'identità dove necessario.

Guardando avanti: un cambiamento fondamentale, non una funzionalità

Project Valhalla rappresenta uno dei cambiamenti più profondi nella storia di Java. Non aggiunge una funzionalità; sposta un'assunzione fondamentale che è rimasta dal 1995: che ogni oggetto ha un'identità. Consentire agli sviluppatori di rinunciare a questo contratto sblocca una nuova era di performance.

JDK 28 è un rilascio non-LTS, con il prossimo LTS probabilmente JDK 29 nel settembre 2027. Questa fase di anteprima è critica per raccogliere feedback dal mondo reale prima che la funzionalità si stabilizzi. Per domini come l'elaborazione dei dati, l'apprendimento automatico, lo sviluppo di giochi e la finanza, la capacità di scrivere codice astratto e sicuro senza sacrificare la densità della memoria è un sogno a lungo perseguito ora alla portata.

Il viaggio non è finito, ma un importante traguardo è stato raggiunto. Come conclude l'articolo, le build di accesso anticipato sono disponibili, consentendo agli sviluppatori di sperimentare con questo nuovo modello prima che diventi mainstream.