Compact Object Headers in Java 25

Naveen AnamaneniUpdated · 4 min read

Compact object headers are a JVM feature that shrinks every object's header from 12 bytes to 8 bytes on 64-bit systems. It was added as an experiment in Java 24 and became a supported product feature in Java 25 (JEP 519), turned on with -XX:+UseCompactObjectHeaders. Because most programs are full of small objects, saving 4 bytes per object can cut heap use noticeably. In this lesson, you will learn how compact headers work and measure the difference.

How It Works

Merging the class pointer into the mark word saves 4 bytes per object

The default header has an 8-byte mark word and a separate 4-byte class pointer. Compact headers squeeze a shorter class pointer into the mark word, so the whole header fits in 8 bytes. Whether an object actually gets smaller depends on padding: the saving shows when the 4 bytes cross an 8-byte boundary.

Example: Measuring the Saving

Let's see an example that measures object sizes with the JVM's class histogram. It is run twice: once normally and once with compact headers.

HeaderSizes.java
import java.lang.management.ManagementFactory;
import javax.management.ObjectName;
 
public class HeaderSizes {
    static class Empty { }
    record Point(int x, int y) { }
    record Student(String name, int marks, boolean passed) { }
 
    static long bytesEach(String className) throws Exception {
        String histogram = (String) ManagementFactory.getPlatformMBeanServer()
            .invoke(new ObjectName("com.sun.management:type=DiagnosticCommand"),
                    "gcClassHistogram", new Object[] {null},
                    new String[] {String[].class.getName()});
        for (String line : histogram.split("\n")) {
            String[] p = line.trim().split("\\s+");
            if (p.length >= 4 && p[3].equals(className)) {
                return Long.parseLong(p[2]) / Long.parseLong(p[1]);
            }
        }
        return -1;
    }
 
    public static void main(String[] args) throws Exception {
        Object[] keep = new Object[300_000];
        for (int i = 0; i < 100_000; i++) {
            keep[i] = new Empty();
            keep[100_000 + i] = new Point(i, i);
            keep[200_000 + i] = new Student("Navika", i, true);
        }
        System.out.println("Empty:   " + bytesEach("HeaderSizes$Empty"));
        System.out.println("Point:   " + bytesEach("HeaderSizes$Point"));
        System.out.println("Student: " + bytesEach("HeaderSizes$Student"));
        System.out.println(keep.length + " objects kept");
    }
}
Terminal
java HeaderSizes.java
java -XX:+UseCompactObjectHeaders HeaderSizes.java
Terminal output
Empty:   16
Point:   24
Student: 24
300000 objects kept
 
Empty:   8
Point:   16
Student: 24
300000 objects kept

Explanation: With compact headers, an empty object needs only its 8-byte header, and Point drops from 24 to 16 bytes (8 + 8, no padding), a 33% saving. Student stays at 24: 8 + 9 bytes of fields = 17, still padded to 24. Programs with many small objects, such as nodes, records and boxed values, gain the most.

Should You Turn It On?

  • Benefits: less heap use, fewer garbage collections, and often better CPU cache use.
  • Status: a supported product option in Java 25, off by default.
  • Test first: measure memory and speed with your real workload before switching production systems.

Common Mistakes

Expecting every object to shrink by 4 bytes. Padding can absorb the saving, as with Student.

Assuming it's on by default in Java 25. It must be enabled with the flag.

Practice

  1. Easy: Predict the size of a record with one int field, with and without compact headers, then measure it.
  2. Harder: Build a linked list of one million nodes, measure heap use with MemoryMXBean after System.gc(), and compare with and without compact headers.

Quick check: Compact object headers

4 questions
1How big is a compact object header?
2Which flag enables compact headers?
3Why didn't the Student record shrink?
4Is it enabled by default in Java 25?

Key Takeaways

Was this tutorial helpful?

Lesson 437 of 482