Java 25 Compact Object Headers Explained
Introduction
Every Java object begins with a hidden object header, which the JVM uses to manage it. On today's 64-bit JVMs that header has taken 12 bytes - often more than the object's actual data. A small object such as a
Measuring the difference
The program below creates 5 million small objects, each holding two
OUTPUT with standard headers
OUTPUT with compact object headers
Explanation of the output
Enabling compact object headers
Point with two int fields carries 8 bytes of data and 12 bytes of header, padded to 24 bytes in all. Java applications create billions of small objects, so headers can account for a large share of the heap. Project Lilliput set out to shrink them, and after an experimental release in Java 24, Java 25Click to read tutorial: Overview of New Features in Java 25 (JEP 519) made compact object headers a product feature: headers shrink to 8 bytes. This tutorial explains what object headers contain, measures the difference with a runnable example, and shows how to enable compact headers.
What is in an object header
Until now, a header on a 64-bit JVM had two parts -
- the mark word (8 bytes) - the object's identity hash code, its age for the garbage collector, and bits used for locking with
synchronized, and - the class pointer (4 bytes with compressed class pointers, the default) - which class the object belongs to.
int fields, keeps them all reachable, and measures how much the used heap grew. That growth divided by the number of objects is the memory each object takes, including its header -
Measuring the memory per small object
//HeaderSize.java
public class HeaderSize {
static final class Point { // 8 bytes of data
final int x, y;
Point(int x, int y) { this.x = x; this.y = y; }
}
static long usedHeap() {
for (int i = 0; i < 3; i++) System.gc();
Runtime rt = Runtime.getRuntime();
return rt.totalMemory() - rt.freeMemory();
}
public static void main(String[] args) {
int count = 5_000_000;
Point[] points = new Point[count]; // the array itself is allocated before measuring
long before = usedHeap();
for (int i = 0; i < count; i++) points[i] = new Point(i, i);
long after = usedHeap();
System.out.printf("Bytes per Point object: about %.1f%n", (after - before) / (double) count);
System.out.println("Points kept: " + points.length);
}
}
java HeaderSize java -XX:+UseCompactObjectHeaders HeaderSize
Bytes per Point object: about 23.9 Points kept: 5000000
Bytes per Point object: about 15.9 Points kept: 5000000
- With standard headers, each
Pointtakes 24 bytes: a 12-byte header, 8 bytes of fields, and 4 bytes of padding to reach a multiple of 8. - With compact headers, each takes 16 bytes: an 8-byte header and 8 bytes of fields, with no padding needed - a third less memory for these objects.
- The saving depends on the object: it is largest for small objects, and for an object whose size was already padded, it can be zero. In real applications, the JEP reports heap reductions of around 10-20%, with corresponding reductions in garbage collection work, and faster execution in some benchmarks thanks to better use of CPU caches.
- Java 24: experimental, enabled with
-XX:+UnlockExperimentalVMOptions -XX:+UseCompactObjectHeaders. - Java 25: a product feature, enabled with just
-XX:+UseCompactObjectHeaders. It is not yet the default; that is expected in a future release once it has been widely used. - It works with all the garbage collectors (G1, Parallel, Serial, ZGC and Shenandoah), and requires no changes to application code.
- A JVM can address a limited number of classes with the compressed 22-bit class pointer - about four million - which is far more than real applications load.
int object taking 24 bytes with standard headers and 16 bytes with compact headers, and saw how to enable the feature in Java 24 and Java 25. Next, read about the Key Derivation Function APIClick to read tutorial: Java 25 Key Derivation Function (KDF) API Tutorial.Continue Reading Java 22 to 25 Tutorials
Overview of New Features in Java 25Click to read tutorial: Overview of New Features in Java 25 Java 25 Compact Source Files and Instance main MethodsClick to read tutorial: Java 25 Compact Source Files and Instance main Methods Java 25 Module Import Declarations with ExamplesClick to read tutorial: Java 25 Module Import Declarations with Examples Java 25 Flexible Constructor Bodies with ExamplesClick to read tutorial: Java 25 Flexible Constructor Bodies with Examples Java 25 Scoped Values Tutorial with ExamplesClick to read tutorial: Java 25 Scoped Values Tutorial with Examples Java 25 Key Derivation Function (KDF) API TutorialClick to read tutorial: Java 25 Key Derivation Function (KDF) API Tutorial Overview of New Features in Java 22Click to read tutorial: Overview of New Features in Java 22 Overview of New Features in Java 23Click to read tutorial: Overview of New Features in Java 23 Overview of New Features in Java 24Click to read tutorial: Overview of New Features in Java 24
Overview of New Features in Java 25Click to read tutorial: Overview of New Features in Java 25 Java 25 Compact Source Files and Instance main MethodsClick to read tutorial: Java 25 Compact Source Files and Instance main Methods Java 25 Module Import Declarations with ExamplesClick to read tutorial: Java 25 Module Import Declarations with Examples Java 25 Flexible Constructor Bodies with ExamplesClick to read tutorial: Java 25 Flexible Constructor Bodies with Examples Java 25 Scoped Values Tutorial with ExamplesClick to read tutorial: Java 25 Scoped Values Tutorial with Examples Java 25 Key Derivation Function (KDF) API TutorialClick to read tutorial: Java 25 Key Derivation Function (KDF) API Tutorial Overview of New Features in Java 22Click to read tutorial: Overview of New Features in Java 22 Overview of New Features in Java 23Click to read tutorial: Overview of New Features in Java 23 Overview of New Features in Java 24Click to read tutorial: Overview of New Features in Java 24