Project Valhalla will reshape the JVM’s object‑centric memory model and open new performance possibilities. As a developer who has processed large data sets on the JVM, I know the typical bottlenecks: every instance carries a header, every reference is a pointer, and the garbage collector has to work constantly. For AI workloads or certain compute-intensive applications this can become a hard limit. Below I describe how Value Types cut that overhead, what pitfalls I ran into while experimenting, and which trade‑offs the new model brings.
Why object overhead kills modern workloads
In today’s JVM almost everything lives on the heap as an object. Even a simple Point with two double fields occupies, besides the two 8‑byte values, an object header of typically a few bytes (depending on compressed oops and pointer size) and is padded to a larger size for alignment. Moreover, an array of objects is really an array of pointers – the data is scattered across memory. This dramatically raises the chance of cache‑misses because the CPU must first fetch the pointer, then follow it to the actual data.
When processing many vectors in numerical simulations or AI models, the “pointer chasing” cost can outweigh the actual computation. Project Valhalla tackles this by introducing Value Classes that behave in memory like primitive types – no header, no pointer, flat layout.
Value Types: primitive‑level performance without syntax churn
The core of Valhalla are value classes. They define classes without identity; == compares the field contents rather than object references. At the bytecode level this can be implemented much more efficiently than a call to equals().
// Classic object (reference type)
public final class PointOld {
public final double x;
public final double y;
public PointOld(double x, double y) { // final fields must be assigned
this.x = x;
this.y = y;
}
}
// Value class (JEP 401, preview) - the actual proposed syntax, not pseudo-code
public value class PointNew { // preview: needs a Valhalla early-access JDK + --enable-preview
public final double x; // 'final' is implicit in a value class
public final double y;
public PointNew(double x, double y) {
this.x = x;
this.y = y;
}
}
An array PointNew[] is stored as a flat sequence of doubles, not as an array of references. This improves locality and lets the JVM emit certain optimizations more effectively because the data is contiguous.
Inline‑Classes and the boxing dilemma
A practical pain point with current Java generics is the forced boxing of primitives (int → Integer). Valhalla adds generic specialization, so List<PointNew> can achieve the same memory efficiency as a hand‑rolled array tuned to the layout of PointNew. This cuts heap pressure and GC work.
The catch is Boxed Escape. When a value instance is cast to an interface or stored in a field of a non‑flattenable object, the JVM must box it again. In a small benchmark I ran, the moment a PointNew escaped into a generic collection, the expected memory savings vanished. The lesson: API design must keep value instances from unintentionally escaping.
Migration pitfalls: identity and synchronization
Losing object identity means synchronized(myValueObject) no longer works – two equal values are indistinguishable for locking. The compiler may provide warnings or errors, highlighting the issue for developers. Likewise, null semantics require careful consideration; missing values may need to be expressed via Optional or explicit sentinel constants to avoid unexpected allocations.
Frameworks that rely heavily on reflection or proxies (e.g., certain ORM frameworks) require substantial rewrites. In a proof‑of‑concept I attempted to replace a JPA entity with a value class; the runtime failed because the persistence provider still expected an identity‑based object.
Implementation status and outlook
Valhalla is still under development. JEP 401 (“Value Classes and Objects”) is the main milestone, and the current OpenJDK roadmap targets JDK 28 for its integration. Early‑access builds are scheduled for late 2025 and early 2026, giving developers a chance to experiment with the features.
Community feedback is cautious: without broad tool support (build tools, libraries) the real impact will only be felt after the official release. Experts such as Simon Ritter (Azul) note that the performance gains become apparent once the ecosystem – compilers, profilers, frameworks – fully embraces the new type system.
Take‑aways for practitioners
- Problem – Object headers and pointer indirection inflate memory usage and increase cache misses.
- Solution – Value Types strip the overhead, eliminate boxing, and enable tighter data layouts.
- What worked – Flat arrays and certain optimizations showed a notable latency reduction in vector‑heavy benchmarks.
- What didn’t work – Unplanned boxing (Boxed Escape) immediately nullified the gains.
- Trade‑offs – No object identity, new failure modes around synchronization, and the need to refactor existing frameworks.
If you are building systems that will benefit from tighter memory footprints, start now by designing APIs that avoid identity‑based contracts and by eliminating unnecessary object allocations. That way you will be ready when JDK 28 ships Valhalla support.
Sources
- The Future of Java Performance — Project Valhalla | Azul - TFiR
- Project Valhalla (Java language) - Wikipedia
- Project Valhalla: Bringing Value Types and Performance Efficiency …
- Project Valhalla - OpenJDK
- Project Valhalla: What It Means for Java Performance
- Project Valhalla, Explained: How a Decade of Work Arrives in JDK 28 - JVM Weekly vol. 180