← Back to news

Project Valhalla, Explained: How a Decade of Work Arrives in JDK 28

jvm-weekly.com|445 points|252 comments|by philonoist|Jun 19, 2026

Project Valhalla, Explained: How a Decade of Work Arrives in JDK 28

The "Ragnarok" of the JVM world is finally here: Project Valhalla is making its way into the JDK.

On June 15, Oracle's Lois Foltan confirmed a milestone that many in the community had begun to doubt: JEP 401: Value Classes and Objects is being integrated into the main OpenJDK repository, with a target release of JDK 28.

The scale of this integration is staggering. The pull request involves:

  • 197,000+ lines of new code.
  • 1,816 modified files.

Because the change is so systemic, other committers were actually advised to pause major commits to ensure the integration went smoothly.

A Word of Caution: Before celebrating, remember that this is a preview feature and is disabled by default. Brian Goetz has reminded us that this is "only the first part of Valhalla." He noted that critics who claimed "they'll never ship it" will likely pivot to complaining that "they didn't ship the most important part." (For years, a running joke in the community suggested we'd reach the Norse afterlife—Valhalla—before the project actually launched).

This deep-dive explores the journey from the original 2014 problem statement through the various failed prototypes, ending with what we can actually expect in JDK 28.


Introduction: The Core Mission

The guiding philosophy of Project Valhalla has always been: "codes like a class, works like an int."

In essence, the goal is to allow developers to write high-level, readable classes—complete with methods, constructors, and named fields—while allowing the JVM to handle them with the raw efficiency of primitive types.

The Fundamental Problem: Reference Types

To understand why this is necessary, we have to look at Java's DNA. Aside from the eight basic primitives (like int, long, and boolean), everything in Java is a reference type.

When you execute Point p = new Point(1, 2), the variable p is not the point itself. Instead, it is a pointer—think of it as a coat-check ticket. The actual object lives somewhere on the heap, and p is just the address used to find it.

This architecture introduces several inefficiencies:

  1. Pointer Indirection: To read a field, the JVM must "go to the coat check," following the pointer to the actual memory location.
  2. Object Overhead: Every object carries a header (roughly a dozen bytes of metadata) used for type identification and synchronization. (Note: Project Lilliput is currently working to reduce this header size).
  3. Allocation Pressure: Every object must be allocated on the heap and eventually cleaned up by the Garbage Collector (GC).
  4. Memory Fragmentation: An array of a million Point objects isn't a contiguous block of data; it's a million pointers leading to a million separate boxes scattered across the heap.

Brian Goetz describes this bloated memory layout as "fluffy."

The Performance Gap: CPU vs. RAM

The real issue is locality of reference. In 1995, accessing memory cost roughly the same as a CPU operation. Today, the CPU is significantly faster—often by two orders of magnitude (10210^2)—than main memory. The only thing bridging this gap is the cache.

The processor fetches memory in cache lines (typically 64 bytes).

Memory LayoutCache EfficiencyResult
Dense (Side-by-side)High: One fetch brings many valuesFast (Cache Hit)
Fluffy (Pointer-based)Low: Every hop risks a missSlow (Cache Miss)

Why "Escape Analysis" Isn't Enough

The JVM does have a trick called escape analysis. If the JIT compiler can prove an object never "escapes" a local scope, it can avoid heap allocation entirely, spreading the fields into registers or local variables.

However, this is a fragile optimization:

  • It is unpredictable.
  • It fails if the object is stored in an array, passed to a complex method, or assigned to a field in another class.
  • A tiny refactor or a JDK update can suddenly disable this optimization, leading to massive, hard-to-trace performance regressions.

The "Brute Force" Alternative

To avoid this, high-performance developers (in game engines, databases, or HPC) often abandon objects entirely and encode data manually.

// The "Brute Force" way: Using a raw array to store RGB colors
// Instead of Color[] colors = new Color[1000];
int[] rawColors = new int[1000]; 
// Risk: Is this RGB? BGR? Who knows? One mistake corrupts the image.

This approach provides speed but destroys safety and readability. Valhalla aims to eliminate this choice between convenient classes and fast primitives.


The Roadmap to JDK 28

Project Valhalla's goals can be summarized as follows:

  • Define Value Classes (JEP 401)
  • Implement Flattening (Dense Memory Layout)
  • Optimize Generic Specialization
  • Finalize Integration into Mainline JDK

Visualizing the Memory Shift

The Long Journey

Officially launched in 2014, Project Valhalla has been a marathon of engineering. James Gosling described it early on as a fundamental shift in how Java handles data. Over the last decade, the team explored five different prototypes, many of which were discarded as they discovered the complexities of maintaining backward compatibility while redefining the JVM's memory model.

As we approach JDK 28, we are finally seeing the first tangible results of this decade-long effort to make Java as fast as C++ without sacrificing the beauty of the object-oriented model.