Back to Blog
App DevelopmentPublished on July 31, 2026

Inside JEP 401: How Value Objects Eliminate Memory Overhead and Pointer Indirection in Modern Java

JEP 401 has officially landed in OpenJDK master, ushering in primitive-like performance for user-defined Java types. Explore how identity-free value objects flatten heap structures, optimize cache locality, and transform high-performance JVM engineering.

The Cost of Object Identity in Traditional Java

For nearly three decades, Java developers have operated under a foundational runtime paradigm: everything that is not a primitive type (int, double, boolean, etc.) is an object instantiated on the heap. While this reference-based object model provided robust abstraction, automatic garbage collection, and clean object-oriented polymorphism, it introduced significant execution overhead for high-performance compute workloads.

Every standard Java object comes wrapped in a mandatory runtime header. On modern 64-bit Java Virtual Machines (JVMs), an object header typically consumes 12 to 16 bytes depending on whether Compressed OOPs (Ordinary Object Pointers) are enabled. This header stores vital runtime metadata, including the lock status, identity hash code, age bits for generational garbage collection, and a reference to the class metadata (Klass word).

Consider a simple 2D coordinate class holding two 64-bit floating-point numbers (double x, double y). The actual payload data is 16 bytes. However, when instantiated as a standard reference object, the JVM allocates 16 bytes for the header plus 16 bytes for the fields, totaling 32 bytes on the heap—a staggering 100% memory overhead.

Furthermore, arrays of such objects do not store raw coordinate values contiguously in memory. Instead, an array of coordinates holds an array of pointers, each referencing an isolated object elsewhere on the heap. This layout causes severe pointer indirection, memory fragmentation, and frequent L1/L2/L3 CPU cache misses. In latency-critical domain processing, financial modeling, real-time telemetry, and high-throughput microservices, this identity overhead represents a major bottleneck.

Deciphering JEP 401: What Are Value Objects?

With the recent merging of JEP 401 (Value Objects - Preview) into the OpenJDK master branch, Project Valhalla reaches a historic milestone. JEP 401 introduces a fundamental enhancement to the Java type system: user-defined objects that declare state without identity.

A value object is declared using the value modifier on a class definition. By designating a class as a value class, the developer explicitly tells the compiler and the JVM that instances of this type do not possess object identity.

Because value objects lack identity, several historical Java runtime properties are intentionally redefined for these types:

  1. No Synchronization: You cannot synchronize on a value object (synchronized(valObj)) because there is no mark word to hold lock state. Attempting to do so results in a compilation error or runtime exception.
  2. Identity-Free Equality: The == operator no longer compares memory heap addresses. For value objects, == performs a field-by-field value comparison (acmp structural equality).
  3. Immutability by Default: All fields of a value class are implicitly or explicitly final. State cannot be altered post-instantiation.
  4. No Identity Hash Code: The System.identityHashCode() for a value object is strictly derived from the hash codes of its fields.
  5. Null-Restricted Types: Value objects lay the groundwork for zero-cost primitive-like types that can be stored flattened in memory without requiring a null reference pointer.
// Declaring a Value Class under JEP 401 Preview
public value class Point3D {
    private final double x;
    private final double y;
    private final double z;

    public Point3D(double x, double y, double z) {
        this.x = x;
        this.y = y;
        this.z = z;
    }

    public double distanceToOrigin() {
        return Math.sqrt(x * x + y * y + z * z);
    }
}

Memory Layout Mechanics: Flattening and Cache Locality

The architectural brilliance of JEP 401 lies in how the C2 Just-In-Time (JIT) compiler and memory manager layout value objects inside memory. Because a value class instance lacks an identity header, the JVM is free to strip the 16-byte object header entirely in optimized contexts.

Contiguous Array Flattening

In classical Java, creating new Point3D[1_000_000] results in 1,000,001 distinct heap allocations: one contiguous array of 1,000,000 pointers, plus 1,000,000 individual Point3D objects scattered across the heap. Inspecting memory addresses reveals non-contiguous locations, rendering hardware prefetching completely ineffective.

Under JEP 401 and Project Valhalla's companion layout enhancements, an array of value objects (Point3D[]) is flattened directly into a contiguous block of memory. The array memory contains the raw sequence of x, y, and z primitive doubles packed back-to-back without headers or pointer references.

| Execution Model | Heap Layout Structure | Memory Footprint (1M Points) | CPU Cache Efficiency | | :--- | :--- | :--- | :--- | | Classic Objects | Array of Pointers -> Heap References | ~40 MB (Headers + Pointers + Payload) | Poor (Constant Pointer Chasing) | | JEP 401 Value Objects | Contiguous Unboxed Bytes | 24 MB (Pure Payload Data) | Optimal (Full Hardware Prefetching) |

By ensuring contiguous layout, modern hardware registers and SIMD (Single Instruction, Multiple Data) vector pipelines can process elements directly from L1 cache lines without suffering from memory access stalls.

Compiler & Runtime Innovations: Calling Conventions and Scalar Replacement

JEP 401 does not merely optimize memory storage on the heap; it fundamentally transforms how Java methods pass arguments across function call stacks.

Register-Based Calling Conventions

When passing a classical object to a method, Java pushes the object's reference (a memory address) onto the call stack or into a register. The receiving method must dereference that pointer to read field values.

With value classes, the JVM calling convention is rewritten. When C2 compiles a hot path receiving a small value object (e.g., a Point3D consisting of three doubles), it unpacks the value object and passes its underlying fields directly across machine registers (xmm0, xmm1, xmm2 on x86_64 or d0, d1, d2 on ARM64). The heap allocation is completely erased, enabling zero-cost abstraction.

Advanced Escape Analysis & Scalar Replacement

While Java's Escape Analysis algorithm could previously dissolve short-lived objects via scalar replacement, it relied on complex escape criteria and frequently failed if the object was passed into non-inlined methods or stored across branches.

Value objects render escape analysis significantly simpler and more aggressive. Because value instances are identity-less and immutable, the runtime compiler can freely duplicate, decompose, re-assemble, or inline fields across execution paths without violating the language specification.

Practical Benchmarks: Processing Financial Order Books

To understand the real-world impact of JEP 401, consider a high-frequency order book engine processing millions of tick updates per second. Each tick contains a price, quantity, timestamp, and asset symbol identifier.

Pre-JEP 401 Object Reference Pattern:

public final class MarketTick {
    private final long timestamp;
    private final double price;
    private final double volume;
    
    // Constructor, getters, and standard boilerplate omitted
}

When iterating over an array of 5,000,000 MarketTick instances to calculate volume-weighted average prices (VWAP), a standard JVM spends a massive percentage of execution time waiting on cache line fills due to memory pointer chasing. Furthermore, the Garbage Collector must periodically scan all 5,000,000 object headers during root-marking phases.

Post-JEP 401 Value Object Pattern:

public value class MarketTick {
    private final long timestamp;
    private final double price;
    private final double volume;
    
    public MarketTick(long timestamp, double price, double volume) {
        this.timestamp = timestamp;
        this.price = price;
        this.volume = volume;
    }
}

With JEP 401 enabled:

  1. Allocation Latency Drops to Zero: Transient allocations inside tight loops are eliminated via scalar register placement.
  2. Garbage Collection Overhead Shrinks: An array of flattened MarketTick values is viewed by G1, ZGC, or Shenandoah as a single contiguous byte array containing no internal object references. Scanning overhead drops from O(N) individual object headers to O(1) contiguous memory region marking.
  3. Throughput Scaling: Benchmark applications executing data crunching workloads routinely demonstrate 2x to 4x throughput improvements while slashing P99 latency spikes caused by GC pauses.

Preparing Your Codebase for Project Valhalla

As JEP 401 enters preview status in current OpenJDK builds, engineering teams can begin auditing and architecting their domain models to leverage value objects seamlessly upon final stabilization.

Migration Guidelines:

  • Audit Value Types: Identify domain DTOs, mathematical abstractions (complex numbers, vectors, matrices), monetary representations, and wrapper identifiers (UUID, MonetaryAmount, GeoCoordinate) that rely purely on state equality.
  • Eliminate Mutability: Convert candidate classes to final immutable structures. Ensure no mutator methods (setX()) exist.
  • Remove Reference Locking: Ensure no code path utilizes domain instances as monitor locks inside synchronized blocks.
  • Avoid Reference Invariants: Replace direct pointer identity checks (a == b) with logical equality (Objects.equals(a, b) or target modern component matching).

JEP 401 represents the most significant structural evolution of the Java execution model since the introduction of Generics in Java 5. By unifying the performance characteristics of primitive types with the expressive abstraction of user-defined classes, OpenJDK master sets a new performance standard for modern enterprise compute ecosystems.

#Java#OpenJDK#JVM#Performance Optimization#Software Architecture