Composition of Java objects

A Java object is in the heap and consists of the Header, Instance Data, and Padding.

  • The object header consists of the mark word, the klass word, and the length of the array. The Klass Word is a pointer to the object’s class metadata (method area), which the JVM uses to determine which class the object is an instance of. Array length: If the object is an array, the object header needs additional space to store the length of the array.

  • Instance data mainly includes the various member variables of an object, including the basic and reference types. Basic types store content directly, reference types are stored Pointers, and static variables are placed in the class, not in the instance data.

  • The main function of alignment padding is to improve the CPU memory access speed, you can refer to the byte alignment of those things

Summary:

If you steal another image, turn on compression, and use the +UseCompressedOops option, klass Word and the array will all be 4 bytes long

Object header Mark Word

Mark Word is used primarily to represent the thread lock state of an object. It can also be used in conjunction with GC and the hashCode that holds the object. For example, on a 64 system, mark Word is 64bit:

The lock bit is 01 for both normal and biased locks, 00 for lightweight locks, 10 for heavy locks, and 11 for GC flags. Since both normal and bias lock are 01, the lower 3 bias lock markers (BIASed_lock) are 0 or 1 to indicate whether they are biased or not.

And then we look sideways,

  • When normally unlocked, mark Word consists of lock, biased_LOCK, age, and identity_hashcode. Age is the GC’s age, up to 15 (4 bits), and increases by 1 for each copy from Survivor. The identity_hashCode is the hashcode of the object, which is moved to monitor when the object is locked (synchronized inserts the monitor before and after the block).

  • In biased locking, Mark Word consists of LOCK, BIASed_LOCK, age, epoch, and Thread. Epoch: Bias lock Indicates the bias identifier of the CAS lock operation, indicating the lock to which the object prefers. Thread: The ID of the thread that holds the biased lock. If the thread accesses the block of the lock again, it can access it directly.

  • In lightweight locking, Mark Word consists of lock, ptr_TO_LOCK_record. Ptr_to_lock_record: Pointer to a lock record in the stack.

  • In heavyweight locking, Mark Word consists of Lock, Ptr_TO_HeavyWeight_monitor. Ptr_to_heavyweight_monitor: pointer to the object Monitor Monitor.

Synchronized lock escalation

Lock upgrade is the process of lock state from normal no lock -> biased lock -> lightweight lock -> heavyweight lock

  1. When the initial lock object is created, no threads are competing with it. The lock state is 01 and the bias lock flag bit is 0 (no threads are competing with it).

  2. When there is a thread competing for a lock, the preference lock is used to indicate that the lock object prefers this thread. This thread will execute any code associated with the lock without any checks and switches. This is very efficient when the competition is not fierce.

  3. When two threads start competing for the lock object, the situation changes and the lock is upgraded to a lightweight lock. The two threads compete fairly. Whichever thread first owns the lock object and executes the code, the lock object’s Mark Word executes the lock record in the stack frame of the thread. Lightweight locks use spin locks in the locking process. Spin means that when another thread is competing for a lock, instead of blocking the thread, it waits in a loop until the thread that acquired the lock releases it, and then it can immediately acquire the lock.

  4. If the thread lock object more competition, led to more switching and waiting, the JVM will lock the object lock escalation to heavyweight lock, this is called the synchronous lock, the lock object Mark Word to change again, will point to a monitor object, the monitor objects in the form of collection, to register and manage the queue of threads. The Monitorenter instruction is inserted at the start of the synchronized block after compilation, and the Monitorexit is inserted at the end of the method and at exceptions. The JVM must ensure that each monitorenter has a corresponding Monitorexit paired with it. When a thread is blocked, it enters the kernel (Linux) scheduling state. This will cause the system to switch back and forth between the user mode and the kernel mode, which seriously affects the lock performance.

For details, see Synchronized Lock Escalation Principle analysis

The pros and cons of locking

The lock advantages disadvantages Applicable scenario
Biased locking Locking and unlocking requires no additional cost and is only nanoseconds away from executing an asynchronous block of code If there is lock contention between threads, there is additional lock undo cost Applies to scenarios where only one thread accesses a synchronized block of code
Lightweight lock Competing threads do not block, making the program more responsive If the lock is never obtained, using spin consumes CPU Pursuit of response time; The synchronized block execution time is very short
Heavyweight lock Thread contention does not use spin and does not consume CPU The thread is blocked and response time is slow Pursue throughput; The synchronized block takes a long time to execute

Memory size of an object

Use the JOL package to see the layout of the objects and how much memory the objects occupy. See the following two articles: Only HotSpot/OpenJDK VMs Are Supported

JOL: View the Java object layout, size tool used by JOL

In addition, Instrumentation can be used to calculate, can refer to the other Instrumentation can be used to calculate