Let's get started with a Microservice Architecture with Spring Cloud:
Reduce Object Header Size and Save Memory in Java 25
Last updated: December 25, 2025
1. Introduction
In this article, we’ll talk about JEP 519 and the significant enhancements it brings to the Java 25 release. This Compact Object Headers JEP aims to transform compact object headers from an experimental version to a full product feature in the HotSpot JVM runtime.
JEP 450 is a precursor to JEP 519, which introduced Compact Object Headers to Java 24. JEP 450’s Compact Object Headers feature plays a crucial role in reducing memory overhead and improving performance for Java applications.
In this article, we’ll primarily focus on Custom Object headers in Java and their impact.
2. Compact Object Headers
JEP 519 introduces Compact Object Headers as an alternative object header layout in JDK 25. The primary goal of this JEP was to reduce the size of object headers in the Hotspot JVM on 64-bit architectures.
2.1. Motivation for Reduction of Object Header Size
The primary goal of this JEP was to reduce the Object Header size from 96 or 128 bits to 64 bits (8 bytes) on 64-bit platforms.
For Java objects averaging 256–512 bits, object headers consume more than 20% of the total footprint. Therefore, this JEP comes with substantial benefits such as:
- Reduction in heap size
- Improvement in the deployment density
- Increased data locality
- Reducing Garbage Collection pressure
2.2. Object Header Structure
In the HotSpot JVM, Java objects are represented with a mandatory header at the start of their memory layout. This header consists of two components: a marker word and a class pointer.
The mark word is a 64-bit field representing the metadata specific to the instance, which consists of:
- The object’s identity hash code
- Information about the Garbage Collection age and forwarding pointers
- Locking and other synchronisation details(monitor state used in synchronised blocks and methods)
We can see this in the table:
| Bits (63-0) | Size (bits) | Purpose |
|---|---|---|
| 63 – 38 | 26 | Unused/Reserved (Can be used for Biased Locking epoch, object address, etc.) |
| 37 – 7 | 31 | Identity Hash Code |
| 6 – 3 | 4 | GC Age (Used by generational collectors like G1 and Parallel GC) |
| 2 – 0 | 3 | Locking State/Flags (Crucial for synchronization) |
On 64-bit systems, the JVM stores the class pointer as a 32-bit compressed reference and uses it to locate the class’s metadata in metaspace. This design lets the JVM perform reflection and type-checking efficiently.
If the object is an array-backed reference, a third field for array length information.
Therefore, it can be deduced that the object header size on 64-bit systems is around 96 and 128 bits.
3. Technical Implementations for Reducing Object Header Size
With JEP 450, a new compact header layout is proposed. The goal of this change is to reduce the average size of Object headers.
3.1. Compact Header Layout
Compact object headers eliminate the division between the mark word and the class pointers. It does that by subsuming the class pointer in compressed form into the mark word.
Therefore, the resulting 64-bit compact object header contains the following fields:
- Compressed class pointer
- Hashcode
- GC Age and Tag information, along with self-forwarded Tag
- An additional 4 bits are reserved for future use by Project Valhalla.
Compressed class pointers should be enabled to use Compact object headers. Furthermore, this compact layout reduces class pointer sizes from 32 bits to 22 bits by altering the encoding scheme.
In the following sections, let’s dig deeper into what went into the technical implementation of this feature.
3.2. Locking Changes
Lightweight locks now work by changing a few tiny bits in the object’s header to show whether the lock is taken or free. Only those specific bits are updated, and nothing else in the header is changed or moved.
Similarly, heavy locks(monitors), which are used in wait/notify scenarios, require the creation of a monitor structure, but only adjust the header’s tag bits. All the other bits are preserved in the new layout.
What’s gone is the old stack-locking path; compact object headers no longer support that legacy mechanism at all.
3.3. GC Forwarding
Hotspot collectors(excluding the ZGC) now relocate objects by writing a forwarding pointer into the object header and preserving only some headers.
With compressed class pointers, a new encoding was introduced. With this encoding, self-forwarding does not destroy header data, and instead, a specific bit signals self-forwarding, and the forwarding address fits into the lower 42 bits.
Finally, full (sliding) GCs, which must preserve every header, are reworked to leverage the new packing scheme.
3.4. Compressed Class Pointers
Compressed Class Pointers have now become mandatory to follow the compact header scheme. This limits the class count to below four million, although this is adequate for all Java applications.
Some JIT compilers, which still do not support this layout, have this feature automatically disabled as a guardrail mechanism.
4. Activation and Benefits
Compact object headers were an experimental feature previously and, therefore, disabled by default. We can enable Compact object headers with the following JVM flags:
- -XX:+UnlockExperimentalVMOptions
- -XX:+UseCompactObjectHeaders.
JEP 519 moves this feature out of the experimental phase. We can enable this product feature with the JVM flag XX:+UseCompactObjectHeaders.
4.1. Memory
Object header size shrinks down to 8 bytes with this change. Therefore, this enables the JVM to reduce the per-object footprint in the heap significantly.
The total memory footprint of applications having many small objects would show a 10-20% reduction in total memory used for live data. Consequently, lower memory consumption means efficiency in hardware, GC, and better deployment density for the cloud and containerised environments.
4.2. Lower GC Pressure
The compact object headers lead to less total heap usage for the same Java workload, leading to less frequent and faster garbage collections. This also leads to reduced GC activity, which internally contributes to lower latency and improved throughput, especially in allocation-heavy workloads.
4.3. Data Locality
Data locality is used to define how close related pieces of data are placed closer to each other in memory. JVMs use data locality to optimize memory efficiency.
With the new layout for the object header, the overall object size decreases. This improves cache-line utilisation and data locality, as more objects can fit within a single CPU cache line. Consequently, it allows the JVM to traverse, manipulate, and move objects with fewer cache misses.
5. Risks and Testing
With increased header bit density and the new header encoding, there is a risk that future JVM features will run out of header bits. This feature also needs extensive testing and benchmarks to validate reliability and performance under concurrent load. Additionally, JVMCI on x64 does not support this compact header structure. The risk is mitigated by turning off the feature when JVMCI is enabled.
The long-term risk is if JVMCI never implements that support for the compact header, which will forever block the migration of the legacy header implementation. Some components that manipulate object headers directly, specifically the Graal compiler as the major user of JVMCI, will have to implement the new header layout. The feature is therefore disabled in such scenarios.
Finally, we’ll talk about the risks associated with project failures. While very unlikely, there is a chance that this feature has irreconcilable functional regressions compared to the legacy header structure. This could be because of the overall reduction in the number of representable classes. Another highly unlikely outcome could be that the compact object headers do not yield tangible real-world improvements, or the upgrades do not justify the overall increase in complexity.
6. Benchmark Results of Custom Object Headers
Although there is no move to enable this object header implementation by default, several benchmark results talk about the strengths and benefits of the feature:
- Benchmarks such as SPECjbb2015 showed a 22% reduction in heap space and 8% less CPU time in one setting
- In another setting, SPECjbb2015 performs 15% fewer garbage collections when running with either the G1 or Parallel collectors (ZGC isn’t supported).
- A highly parallel JSON parser benchmark runs in 10% less time
7. Conclusion
In this article, we talked in depth about JEP 519’s compact Object Header feature. This feature aims to provide significant gains in performance and space efficiency by reducing object header size.
We also dove into how this feature was internalised and the modifications done on the locking and GC forwarding header information. Overall, this feature makes the JVM future-ready.















