Fundamentals 13 min read

Understanding Java Object Memory Layout, Size of new Object() and Heap Allocation

This article explains how Java objects are laid out in memory, compares the heap locations of fields and local variables, analyzes the byte size of a plain new Object() with and without compressed oops, demonstrates measurement using JOL, and reviews related heap regions and garbage‑collection concepts.

Architect's Tech Stack
Architect's Tech Stack
Architect's Tech Stack
Understanding Java Object Memory Layout, Size of new Object() and Heap Allocation

In Java interview questions, a common tricky query is how many bytes a new Object() occupies. To answer this, we need to understand the JVM's heap layout and the memory structure of Java objects.

Object References

Consider the following code:

package com.zwx.jvm;

public class HeapMemory {
    private Object obj1 = new Object();

    public static void main(String[] args) {
        Object obj2 = new Object();
    }
}
123456789

Here obj1 is a field stored in the heap, while obj2 is a local variable stored in the JVM stack frame.

Java Memory Model

A Java object consists of three parts: the object header (Mark Word + Class Pointer), the instance data, and optional padding for alignment. On a 64‑bit JVM without compressed oops, the layout looks like:

The object header stores synchronization information (Mark Word) and a pointer to the class metadata. Padding is added only when the total size is not a multiple of 8 bytes.

Object Size of new Object()

Based on the layout, the size of a plain object on a 64‑bit JVM is:

Without compressed oops: 8 bytes (Mark Word) + 8 bytes (Class Pointer) = 16 bytes

With compressed oops (default): 8 bytes (Mark Word) + 4 bytes (compressed Class Pointer) + 4 bytes (padding) = 16 bytes

We can verify this using the JOL library.

<dependency>
    <groupId>org.openjdk.jol</groupId>
    <artifactId>jol-core</artifactId>
    <version>0.10</version>
</dependency>
12345
package com.zwx.jvm;

import org.openjdk.jol.info.ClassLayout;

public class HeapMemory {
    public static void main(String[] args) {
        Object obj = new Object();
        System.out.println(ClassLayout.parseInstance(obj).toPrintable());
    }
}
12345678910

Running the demo prints a 16‑byte size, confirming the default compressed‑oops configuration.

Disabling compressed oops with JVM flags:

-XX:+UseCompressedOops  // enable (default)
-XX:-UseCompressedOops  // disable
12

After disabling, the printed size remains 16 bytes because padding compensates for the larger class pointer.

Object with a Field

When a class contains a byte field, the size changes:

package com.zwx.jvm;

public class MyItem {
    byte i = 0;
}
12345
package com.zwx.jvm;

import org.openjdk.jol.info.ClassLayout;

public class HeapMemory {
    public static void main(String[] args) {
        MyItem myItem = new MyItem();
        System.out.println(ClassLayout.parseInstance(myItem).toPrintable());
    }
}
12345678910

With compressed oops the object occupies 16 bytes; without compressed oops it occupies 24 bytes, demonstrating the memory‑saving effect of compressed references.

Object Access

There are two main ways the JVM accesses objects:

Handle access : the object stores a handle address; the handle pool stores the actual instance and class pointer.

Direct pointer access (used by HotSpot): the object stores the class pointer directly.

Handle access adds an extra indirection but allows the object to be moved without updating all references; direct pointer access is faster but requires updating references when the object moves.

Heap Regions

The Java heap is divided into Young and Old generations. Objects are first allocated in the Young generation (Eden), then survive GC cycles and move to Survivor spaces (S0, S1) before being promoted to the Old generation.

When Eden fills, a Minor GC copies surviving objects to a Survivor space. If a Survivor space becomes full, objects are copied to the other Survivor space, and the empty space becomes the new target. If both Survivor spaces are full, objects are promoted to the Old generation, which may trigger a Full GC.

GC Terminology

GC – Garbage Collection

Minor GC – collection of the Young generation

Major/Full GC – collection of both Young and Old generations

Eden – the primary allocation area in the Young generation

Survivor (S0, S1) – spaces that hold objects that survived a Minor GC

Old – the tenured generation for long‑lived objects

Understanding these regions and the object layout helps explain why a new Object() consistently occupies 16 bytes on a typical 64‑bit JVM with compressed oops enabled.

Conclusion

This article introduced the memory layout of Java objects, measured the size of a plain new Object() under different JVM settings, compared handle and direct pointer access, and reviewed the structure of the heap and basic GC concepts. Further details on GC algorithms and collectors will be covered in a future article.

JavaJVMgarbage collectionObject Memory Layoutcompressed-oops
Architect's Tech Stack
Written by

Architect's Tech Stack

Java backend, microservices, distributed systems, containerized programming, and more.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.