Fundamentals 20 min read

Understanding Java Object Memory Layout, Monitor, and Synchronization Mechanisms

This article explains the JVM object memory layout—including object header, instance data, and alignment padding—details the structure of the Mark Word and Klass Word, describes how monitors and the synchronized keyword work at the bytecode level, and covers lock states, inflation, bias revocation, and spin optimizations with practical code examples.

JD Retail Technology
JD Retail Technology
JD Retail Technology
Understanding Java Object Memory Layout, Monitor, and Synchronization Mechanisms

In the JVM, every Java object consists of three memory regions: the object header, instance data (including fields from super‑classes), and alignment padding to satisfy 8‑byte alignment requirements.

The object header is divided into two parts: the Mark Word and the Klass Word . For arrays, an additional array length field is stored.

The Mark Word (one machine word) encodes several pieces of information:

lock : 2‑bit lock state.

biased_lock : 1‑bit indicating whether biased locking is enabled.

age : 4‑bit object age used by the GC.

identity_hashcode : 25‑bit hash code (lazy‑loaded).

thread : thread ID that holds a biased lock.

epoch : timestamp for biased locking.

ptr_to_lock_record : pointer to the lock record in the thread stack.

ptr_to_heavyweight_monitor : pointer to the heavyweight monitor.

The Klass Word stores a pointer to the object's class metadata, allowing the JVM to identify the object's type.

When a synchronized block is entered, the JVM associates a Monitor (also called a monitor object) with the target object. The monitor contains an owner field, an entry list of blocked threads, and a wait set for threads that called wait() .

At the bytecode level, the synchronized construct is compiled into MONITORENTER and MONITOREXIT instructions. The following snippet shows a simple synchronized method and its corresponding bytecode:

static final Object lock = new Object();
static int counter = 0;
public static void main(String[] args) {
    synchronized (lock) {
        counter++;
    }
}

public static main([Ljava/lang/String;)V
TRYCATCHBLOCK L0 L1 L2 null
TRYCATCHBLOCK L2 L3 L2 null
L4
LINENUMBER 6 L4
GETSTATIC MyClass03.lock : Ljava/lang/Object;
DUP
ASTORE 1
MONITORENTER // 注释1
L0
LINENUMBER 7 L0
GETSTATIC MyClass03.counter : I
ICONST_1
IADD
PUTSTATIC MyClass03.counter : I
L5
LINENUMBER 8 L5
ALOAD 1
MONITOREXIT // 注释2
L1
GOTO L6
L2
FRAME FULL [[Ljava/lang/String; java/lang/Object] [java/lang/Throwable]
ASTORE 2
ALOAD 1
MONITOREXIT // 注释3
L3
ALOAD 2
ATHROW
L6
LINENUMBER 9 L6
FRAME CHOP 1
RETURN
L7
LOCALVARIABLE args [Ljava/lang/String; L4 L7 0
MAXSTACK = 2
MAXLOCALS = 3

Annotation 1 explains that MONITORENTER attempts to acquire the monitor; if the entry count is zero, the current thread becomes the owner. If another thread already holds the monitor, the current thread blocks.

Annotation 2 describes MONITOREXIT , which decrements the entry count and releases ownership when it reaches zero, waking blocked threads.

The JVM uses several lock states:

Biased lock : optimizes uncontended synchronization by recording the owning thread ID in the Mark Word.

Lightweight lock : uses a lock record on the thread stack and a CAS operation to replace the Mark Word with a pointer to that record.

Heavyweight lock : falls back to a full monitor object when contention occurs (lock inflation).

Lock inflation occurs when a CAS fails because another thread already holds a lightweight lock, causing the JVM to allocate a heavyweight monitor and link the object to it.

Spin‑lock optimization can be applied to heavyweight locks: a thread may spin for a short period before blocking, reducing context‑switch overhead on multi‑core CPUs.

Biased lock revocation happens when contention appears or when the object's hashCode is computed; the Mark Word’s bias bit is cleared and the lock may be upgraded.

Re‑biasing allows an object that was previously biased to a thread to be re‑biased to another thread after a configurable number of revocations (default 20). Bulk revocation occurs when the revocation threshold is exceeded (e.g., 40), causing the JVM to disable biased locking for the entire class.

Various code examples in the article demonstrate these concepts, including:

static final Object obj = new Object();
public static void method1() {
    synchronized (obj) { // sync block A
        method2();
    }
}
public static void method2() {
    synchronized (obj) { // sync block B
    }
}

and tests that show how invoking hashCode() , using wait() / notify() , or multiple threads accessing the same object affect lock state transitions.

Overall, the article provides a comprehensive view of how the JVM implements synchronization, from object header layout to monitor structures, bytecode instructions, lock states, inflation, bias revocation, and performance optimizations.

JavaJVMConcurrencyLocksynchronizedMonitorObject Memory Layout
JD Retail Technology
Written by

JD Retail Technology

Official platform of JD Retail Technology, delivering insightful R&D news and a deep look into the lives and work of technologists.

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.