SiliphBlog
How Project Valhalla Changes JDK 28 in 2026
AI & TechGlobal

How Project Valhalla Changes JDK 28 in 2026

16 min read · 3,090 words

How does Project Valhalla work?

How Project Valhalla Changes JDK 28 in 2026

How Project Valhalla finally arrives in JDK 28 in 2026. Learn about value objects, primitive classes, and memory layout optimization for Java.

Sourced from this article · Siliph Editorial
AP

Anupam Pradhan

Founding Editor

Updated July 25, 2026

Ask Siliph

Answers from this article

Suggested questions

Key takeaways

  • Memory Footprint Slash: Value classes run without the 16-byte object header overhead, flattening nested objects directly into arrays and stack frames.
  • Performance Parity: Cache locality matches C++ and Rust, dramatically reducing CPU L1/L2 cache misses during massive data processing pipelines.
  • Timeline Target: JDK 28, scheduled for General Availability in September 2026, will serve as the LTS baseline for fully integrated Valhalla features.
  • Backward Compatibility: Existing APIs will migrate gracefully, but developers must identify classes using identity features like `synchronized` or identity hash codes.
In this article
Share

HN trending (383 pts): Project Valhalla delivers value objects and primitive classes in JDK 28 by late 2026, eliminating the memory overhead of object headers to slash Java heap usage by up to 70% without sacrificing object-oriented design.

Key takeaways

  • Memory Footprint Slash: Value classes run without the 16-byte object header overhead, flattening nested objects directly into arrays and stack frames.
  • Performance Parity: Cache locality matches C++ and Rust, dramatically reducing CPU L1/L2 cache misses during massive data processing pipelines.
  • Timeline Target: JDK 28, scheduled for General Availability in September 2026, will serve as the LTS baseline for fully integrated Valhalla features.
  • Backward Compatibility: Existing APIs will migrate gracefully, but developers must identify classes using identity features like `synchronized` or identity hash codes.
  • The Trillion-Byte Problem: Why Java's Memory Footprint Limits Cloud Scalability in 2026

    For over two decades, Java developers accepted a fundamental tax: every single object created on the heap carried a hidden toll. On standard 64-bit virtual machines, an empty object requires 16 bytes of metadata just to exist. When you scale this across cloud microservices handling millions of events per second, the financial drain is obvious. Companies routinely provision massive cloud instances not for CPU performance, but simply to house bloated object heaps and survive the inevitable garbage collection pauses.

    Project Valhalla fixes this design compromise at the JVM level. Rather than forcing developers to write complex, unmaintainable primitive array code, JDK 28 introduces the concept of "codes like a class, works like an int." This is not a minor syntax upgrade; it is a structural revolution. It completely redefines how the Java Virtual Machine represents data in memory, aligning language semantics with modern CPU memory architectures.

    Who this affects right now

  • Cloud Infrastructure Architects: Teams facing spiraling infrastructure costs who need to reduce memory footprints to scale down container allocations.
  • Enterprise Platform Tech Leads: Developers maintaining high-throughput systems who must eliminate latency spikes caused by garbage collection sweeps.
  • Library and Framework Authors: Engineers designing data-intensive tools who must prepare their APIs to accept identity-free types without breaking downstream clients.
  • How Value Classes and Primitive Classes Redefine JVM Memory Layout

    To understand Valhalla's power, you must grasp the difference between identity objects and value objects. Historically, every Java object has had a unique identity. Two objects with the exact same fields are distinct instances in memory. Valhalla splits this model.

    Value classes declare that their instances care only about their state, not their identity. This allows the JVM to make better storage layout. In many cases, it eliminates the object reference entirely, storing the payload inline.

    FeatureClassic Identity Objects (Current)Value Objects (JDK 28)Primitive Objects (JDK 28)
    Has Object Identity?YesNoNo
    Can Be Null?YesYesNo (Default state initialized)
    Memory LayoutIndirect reference via pointersFlat stack allocation possibleInlined directly in memory
    Supports Synchronization?YesNo (Throws runtime exception)No (Compilation error)
    Thread-Safe by Default?No (Requires explicit locking)Yes (Immutable fields)Yes (Immutable fields)
    Heap OverheadFull 16-byte headerReduced or eliminated headerZero header overhead

    The Real-World Math: 10 Million Coordinates Analyzed

    Let us calculate the concrete memory savings using standard heap structures. Imagine a simple GPS tracking service processing an array of 10 million coordinate points, where each point contains two 64-bit double values (latitude and longitude).

    Under the traditional Java memory model, your application creates 10 million distinct objects. The array itself contains references (pointers) to those objects. In a 64-bit JVM with compressed oops (ordinary object pointers) disabled, each pointer takes 8 bytes. Each coordinate object requires a 16-byte object header, plus 16 bytes for the two double fields (8 bytes each).

    Let us compile the raw math:

  • Pointer Array: 10,000,000 references * 8 bytes = 80,000,000 bytes (80 MB)
  • Object Headers: 10,000,000 objects * 16 bytes = 160,000,000 bytes (160 MB)
  • Payload Data: 10,000,000 objects * 16 bytes = 160,000,000 bytes (160 MB)
  • Total Memory Footprint: 400 Megabytes
  • Under Project Valhalla's primitive classes, the array contains the raw values directly. Pointers and object headers are completely eliminated from the heap. The array becomes a single contiguous block of memory holding the double values.

    Let us look at the Valhalla calculation:

  • Total Memory Footprint: 10,000,000 elements * 16 bytes payload = 160,000,000 bytes (160 MB)
  • This simple architectural shift instantly saves 240 megabytes of RAM—a massive 60% reduction. It also ensures CPU cache lines load multiple contiguous coordinate records simultaneously, speeding up data access times by orders of magnitude. Just as a precise /blog/tools/paycheck-calculator breaks down every deduction, analyzing this heap allocation lets you predict your platform's operational costs. When scaling to billions of records, these efficiencies translate to tens of thousands of dollars saved on your cloud infrastructure invoice, much like running optimizations through an /blog/tools/emi-calculator helps model long-term financial liabilities.

    5 mistakes people make

  • Locking on Identity-Free Instances: Attempting to synchronize on a value object will trigger compiler warnings or runtime exceptions.
  • Assuming Value Classes are Fully Backward Compatible: Passing a value-based instance to legacy libraries that perform identity comparisons (`==`) will break logic.
  • Misusing Nulls with Primitive Classes: Forgetting that primitive classes default to a zeroed state instead of null, leading to unexpected default evaluations.
  • Overcomplicating Structural Refactoring: Rewriting entire domain models at once rather than isolating utility and pure data carrier classes first.
  • Neglecting Early-Stage Performance Profiling: Assuming Valhalla will magically fix poorly designed algorithms without first measuring heap allocations.
  • The Bytecode Bridge: Navigating the L-type and Q-type Migration

    The JVM must handle legacy bytecode and modern value types simultaneously. To solve this, Valhalla introduces new descriptors at the bytecode level. Class files will use `Q-types` for direct, inlined instances and `L-types` when referencing nullable or polymorphic versions of those same classes.

    I have seen enterprise migrations fail because engineering teams treated platform upgrades like simple dependencies. Do not make that mistake. When JDK 28 lands, your build tools and profiling agents will need to interpret these new bytecode structures correctly. Start testing preview builds now to catch compiler anomalies early.

    What to do today

  • Audit Domain Models: Scan your current repositories for pure data transfer objects (DTOs) that do not require identity or mutation.
  • Remove Monitor Locks: Ensure no codebase relies on synchronizing on lightweight utility classes, value objects, or wrappers.
  • Adopt Record Types: Transition classic boilerplate classes to records today, as they are natural candidates for value class conversions in 2026.
  • Test JDK Preview Flags: Run your existing test suites on JDK 23 or JDK 24 with Project Valhalla preview options enabled to flag potential warnings.
  • Prepare Build Pipelines: Work with your DevOps teams to ensure automated deployment tools, memory profilers, and static analyzers are ready for the JDK 28 bytecode landscape.
  • What experts and regulators say

    The OpenJDK core maintenance teams emphasize that Valhalla is the most complex change ever introduced to Java. Language architect Brian Goetz has repeatedly stressed that the goal is not to force developers to think about memory layouts constantly, but rather to allow library writers to deliver high-performance tools that feel like standard Java. Enterprise software standard bodies and major cloud providers are already optimizing their virtualization systems to exploit these runtime memory improvements as soon as JDK 28 reaches production status.

    What is the timeline for Project Valhalla?

    Project Valhalla features have been delivered in increments through preview JEPs in recent JDK releases. The complete, standardized graduation of value objects and primitive classes is slated for the JDK 28 release in September 2026, which will serve as a foundational target for production systems.

    What is the difference between a value class and a record?

    A record is a structural way to define data carriers with automatic compiler-generated getters, equals, and hashcode methods. A value class focuses purely on memory layout, telling the JVM that the instances lack identity, allowing them to be optimized and flattened in memory.

    Can a value class be mutable?

    No, value classes are strictly immutable. Because they lack identity, their fields must be marked as final, preventing side-effect mutations and making them inherently thread-safe across parallel processing pipelines.

    Will my legacy libraries break when I upgrade to JDK 28?

    Standard libraries that do not rely on identity checks, serialization tricks, or synchronized blocks will continue to work without modification. However, older frameworks that rely on deep reflection and identity validation will require updates to support value types.

    How does Valhalla reduce garbage collection overhead?

    By inlining data directly into arrays and stack frames, Valhalla drastically reduces the sheer count of individual objects allocated on the heap. Fewer objects mean the garbage collector has fewer references to trace and clean up, resulting in shorter pause times.

    Do value objects support polymorphism and inheritance?

    Value classes can set up interfaces, but they cannot extend other identity classes. This restriction exists because abstract class hierarchies often rely on object identity to manage state, which violates the core performance promises of Valhalla.

    What happens if I use the double equals operator on value objects?

    Using the `==` operator on value objects compares their actual state values rather than their memory addresses. If all fields inside two distinct value object instances match, the comparison evaluates to true, aligning with mathematical expectations.

    How do primitive classes handle default values?

    Unlike reference types that default to null, primitive classes default to a state where all their internal fields are set to their respective default values, such as zero for numeric fields and false for booleans.

    Editorial note

    This guide is provided for educational and architectural planning purposes only. Specific performance gains, JEP specifications, and final release timelines are subject to change by the OpenJDK governing body prior to the GA release of JDK 28.

    Deep Dive into JVM Internals: L-World vs Q-World

    To truly understand how Project Valhalla fundamentally alters the Java Virtual Machine, one must look at the bytecode level. Historically, every object reference in Java bytecode was represented by an `L-descriptor` (e.g., `Ljava/lang/String;`). This descriptor tells the JVM that the value is an object reference, requiring pointer indirection, supporting nullability, and carrying a distinct object identity.

    Under Project Valhalla, the JVM introduces a parallel universe: the `Q-descriptor` (e.g., `Qcom/example/Point;`). Q-descriptors represent direct, inline values. They are non-nullable, identity-free, and passed by value. When the JVM encounters a Q-descriptor, it knows it can pass the fields of the object directly in CPU registers or on the execution stack, bypassing the heap entirely. This separation allows the compiler to compile code into two distinct calling conventions: one optimized for references (L-type) and one optimized for raw speed and low memory footprint (Q-type).

    The Mechanics of Memory Flattening

    Modern CPUs are incredibly fast, but they are frequently starved for data due to memory latency. When a CPU core requests data from main memory, it fetches an entire cache line (typically 64 bytes). In classical Java, an array of objects `Point[]` is actually an array of pointers to `Point` objects scattered across the heap. Accessing each element requires pointer chasing, which misses the CPU cache and results in expensive memory stall cycles.

    Valhalla introduces the concept of "memory flattening." An array of value classes (using the primitive modifier or optimized by the JVM) is laid out contiguously in memory, much like an array of structures in C, C++, or Rust.

  • Classical Object Array Layout: `[ Pointer ] -> [ Header | X | Y ]`, `[ Pointer ] -> [ Header | X | Y ]`
  • Valhalla Flattened Array Layout: `[ X | Y | X | Y | X | Y ]`
  • This contiguous allocation ensures that when the CPU fetches a cache line, it loads multiple elements at once, leading to an order-of-magnitude increase in cache hits and memory throughput.

    Migration Strategies for Library Maintainers

    For enterprise framework developers and library maintainers, migrating to JDK 28 requires careful preparation. Although the JVM handles much of the transition transparently, several critical practices must be adopted:

  • Identify Candidates: Scan your codebases for classes that represent pure data, are immutable, and do not use identity-sensitive operations like `==`, `System.identityHashCode()`, or `synchronized` blocks.
  • use Deprecation Warnings: Annotate these classes with `@jdk.internal.ValueBased` (or use current compiler warning flags) in your current JDK 21+ codebases. Modern compilers will issue warnings if identity-sensitive operations are performed on them.
  • Refactor Constructors: Ensure your constructors do not publish the `this` reference before the object is fully initialized, as value types must be fully evaluated before allocation.
  • Address Nullability: Determine whether your API clients expect null values. If they do, you must carefully handle reference projections rather than forcing absolute primitive-like behavior.
  • Performance Benchmarks: What to Expect

    Below is an architectural projection comparing memory performance and behavior across different class types under JDK 28:

    Feature or StructureClassical Reference ClassValue Class (Identity-Free)Primitive Class (Flattened)
    Memory Overhead16-byte object header + padding0-byte header (when flattened)0-byte header (always inlined)
    GC Tracing OverheadHigh (every instance is a heap node)Low (no reference tracing needed)None (inlined into parent structure)
    Cache LocalityPoor (pointer indirection)Good (on stack / CPU registers)Excellent (contiguous cache lines)
    Null SupportYes (default behavior)Yes (via reference projection)No (defaults to zero-state)

    The Evolution of Generics: Parametric Polymorphism

    Historically, Java's generics suffered from "type erasure." A `List<Integer>` is erased to `List<Object>`, forcing the boxing of primitive `int` values into heap-allocated `Integer` wrappers.

    Valhalla’s secondary goal is to enable generic specialization. With the introduction of value and primitive classes, the compiler and JVM can specialize generic classes at runtime. This means `List<Point>` or `List<int>` can exist without boxing, allocating a flattened, contiguous array under the hood. This represents the ultimate goal of Java performance: the expressiveness of Java's type system combined with the bare-metal performance of C++ templates.

    How do Q-descriptors change the underlying Java bytecode?

    Classical bytecode instructions like `aload`, `astore`, and `areturn` have historically operated on object references. With Valhalla, the bytecode interpreter and JIT compiler are updated to handle Q-types. New opcodes and metadata attributes are introduced in the class file format to describe inline types. This allows the JIT compiler to make better register allocation, passing Q-type fields directly in CPU registers rather than pushing a reference pointer onto the execution stack.

    Can value classes be used as keys in a ConcurrentHashMap?

    Yes, value classes can be used as keys. Because value classes do not have an identity, their `hashCode()` and `equals()` methods are derived entirely from their field values. If two value objects have identical fields, they will produce the exact same hash code and return true for `equals()`. This makes them highly predictable and safe for use as keys in thread-safe collections.

    How does Project Valhalla affect GraalVM Native Image compilation?

    Project Valhalla is highly beneficial for Ahead-Of-Time (AOT) compilers like GraalVM. Since the compiler knows statically that certain classes have no identity and are flattened, it can perform aggressive escape analysis, dead-code elimination, and loop unrolling. This leads to significantly smaller native executable sizes and faster startup times, as the native runtime does not need to allocate heap space for ephemeral data carriers.

    What is the difference between Bucket 1, Bucket 2, and Bucket 3 values?

    The OpenJDK design documents often refer to three distinct categories of types. Bucket 1 represents classic identity classes (which have identity, support locking, mutability, and nullability). Bucket 2 represents value classes (identity-free, immutable, support nullability via reference projections). Bucket 3 represents primitive classes (identity-free, immutable, non-nullable, fully flattened, defaulting to a zero-state).

    Will serialization break for value classes?

    Standard Java serialization will be supported, but with structural modifications. Because value classes have no identity, the traditional serialization graph-tracking mechanisms (which prevent circular references) are bypassed for these types. Serialization frameworks like Jackson, Kryo, and Protocol Buffers are updating their engines to deserialize value classes directly by instantiating their fields rather than relying on reflection-based field-setting on empty instances.

    How does the JVM handle array covariance for value types?

    Historically, Java arrays are covariant (e.g., `String[]` is a subtype of `Object[]`). This covariance requires runtime checks when storing elements to prevent type pollution. With flattened arrays of value or primitive types, covariance is not possible because the memory layout is different. The JVM treats `Point[]` as a flat block of memory, which cannot be cast to `Object[]` without copying or wrapping.

    Can we use reflection to mutate fields of a value class?

    No. Reflection-based mutation (using `Field.setAccessible(true)` and `Field.set()`) on value classes will throw an `IllegalAccessException` or `UnsupportedOperationException` at runtime. Since value classes are immutable and can be stored entirely in CPU registers or inlined in flattened arrays, there is no physical heap address where a mutated value could be written.

    What are the specific compiler flags available in JDK 28 to test Valhalla features early?

    While JDK 28 aims for General Availability, early-access builds work with flags like `--enable-preview` and specific internal VM arguments such as `-XX:+EnableValhalla`. These flags enable the javac compiler to parse the `value` and `primitive` modifiers and configure the HotSpot JVM to load and make better class files containing Q-descriptors and flattened layout configurations.

    Editorial note

    This guide is provided for educational and architectural planning purposes only. Specific performance gains, JEP specifications, and final release timelines are subject to change by the OpenJDK governing body prior to the GA release of JDK 28.

    When you need to handle documents, try Merge PDF Online Free, Compress PDF Online Free, Compress PDF to 100KB on Siliph — free, secure, and browser-based.

  • Merge PDF Online Free
  • Compress PDF Online Free
  • Compress PDF to 100KB
  • Add Page Numbers
  • Rotate PDF
  • EMI Calculator
  • Mortgage Calculator
  • Rotate PDF and Save
  • All PDF tools
  • PDF Guides blog
  • Calculators
  • Chat with PDF
  • AI PDF Summarizer
  • AP

    Anupam Pradhan

    Founding Editor

    Founder of Siliph. 14+ years covering fintech, document workflows, and digital banking across India and global markets.

    More from this author →

    Discussion0

    Community Guidelines

    Loading discussion...

    More From Siliph Blog