Object Memory Layout -JOL(Java Object Layout)
package pro.eddie.demo;
import org.openjdk.jol.info.ClassLayout;
public class JavaObjLayout {
public static void main(String[] args) {
Demo demo = new Demo();
System.out.println(ClassLayout.parseInstance(demo).toPrintable());
}
private static class Demo {
private int i = Awesome!;
private int j = 777; }}Copy the code
Running results:
You can see that the object layout is divided into four parts:
- MarkWord: records the state of the object, including: no lock state, lock state (bias lock, spin lock, weight lock), GC mark state.
- Class type pointer: This pointer is used to quickly locate the corresponding class class, which is used to access the getClass() method
- Instance data: Stores attributes in an object. VALUE is the corresponding VALUE in the case of a primitive data type, and object references in the case of an object
- Alignment: On 64-bit operating systems, the alignment part will automatically fill up the object’s memory to a size divisible by 8, which is easy to manage and address, but also avoids fragmentation
Biased locking and its application scenarios
A bias lock is implemented as follows: one bit of the MarkWord in the Unlock state identifies whether the bias lock is used or disabled. If the bit is 0, the object is not locked and bias is prohibited. If the bit is 1, it means that the object is in the bias lock state. The default object is Anonymously biased. This can be changed to Rebiasable or biased once there is a thread using the object. At this time, other threads will access the object again, and determine whether the thread holding the object is using the object. If not, the object is in Rebiasable ** state. Through CAS atomic operation, the bias lock of the object is bound to the thread itself.
Application scenario: This mode is applicable to single-thread operations. If there are more than one threads, biased locks can be easily upgraded to lightweight locks. Revoking biased locks also consumes resources.
Lightweight locks/spin locks and their application scenarios
Lightweight/spin locks are CAS
Application scenario: A small number of concurrent threads, and the execution time of each thread is short; Cause: THE CAS operation still occupies CPU resources (value, assignment, and comparison). If the number of threads is large, the execution time of the thread is long, resulting in a large number of spins of the thread, which is not worth the loss.
Heavyweight locks and their application scenarios
Implementation: Each Java object is associated with a Monitor binding, and when a thread wants to execute the contents of a Synchronized block, it first takes the object’s Monitor. And has the following rules:
If the entry number of the monior is 0, the thread can enter monitor and set the entry number of monitor to 1. The current thread becomes the owner of monitor
If the thread already owns monitor, it is allowed to re-enter monitor and increment the number of monitor entries
If another thread already has ownership of Monitor, the thread currently trying to acquire ownership of Monitor is blocked until the monitor’s entry count becomes zero
The thread that can execute monitorexit must be the one that owns the monitor of the current object, and the monitorexit will decrease the monitor’s entry count by one when executed.
When the number of monitor entries decreases to 0, the current thread exits the monitor and no longer owns the monitor. At this point, other threads blocked by the Monitor can try to acquire the ownership of the monitor
The Monitor implemented by HotSpot is ObjectMonitor written by Cpp:
ObjectMonitor() {
_header = NULL;
_count = 0; / / monitor into the number
_waiters = 0,
_recursions = 0; // The number of threads reentrant
_object = NULL;
_owner = NULL; // Identifies the thread that owns the monitor
_WaitSet = NULL; _WaitSet is the first node in the list
_WaitSetLock = 0 ;
_Responsible = NULL ;
_succ = NULL ;
_cxq = NULL ; // Multi-threaded contention lock entry when the single necklace table
FreeNext = NULL ;
_EntryList = NULL ; // Threads in the waiting block state are added to the list
_SpinFreq = 0 ;
_SpinClock = 0 ;
OwnerIsThread = 0 ;
}
Copy the code
- Owner: The initial value is NULL. When a thread owns the Monitor, the owner flag is the unique identifier for the thread. When the thread releases monitor, owner returns to NULL. The owner is a critical resource that the JVM keeps thread safe through CAS operations.
- CXQ: Contention queue. All threads requesting locks are first placed in this queue (one-way link). CXQ is a critical resource and the JVM modifs the _CXQ queue with CAS atomic instructions. The old value of _cxq before the change is inserted into node’s next field, and _CXq points to the new value (new thread), so _CXq is a last-in, first-out stack.
- Threads in the _EntryList: _CXQ queue that qualify as candidate resources are moved to the queue
- _WaitSet: Threads blocked by calling the wait method are placed in this queue
Application scenario: Multi-threaded concurrent execution takes a long time. When an object is locked, other concurrent threads block and do not occupy CPU resources.
Lock upgrade process (no lock -> partial lock -> Lightweight lock -> Heavyweight lock)
-
No lock -> Bias lock:
By default, bias locking is enabled after 4 seconds of execution by the main thread.
Reason: The JVM itself has some default threads to start, there is a lot of sync code, this code starts, there is lock contention, if biased lock, there will be a lot of lock cancellation, lock upgrade operations, which makes the efficiency of slow.
-
Biased locks -> Lightweight locks:
4 seconds after the program starts, biased lock mechanism is enabled by default. When a thread accesses the object marked by MarkWord as biased lock for the first time (anonymous biased), MarkWord is modified to point to this thread. When the second thread accesses the object and finds that the biased lock of the object is held, it accesses the thread through the thread information on MarkWord and determines whether the thread still needs to hold the biased lock. If the thread does not need to continue to hold the object, it can revoke the biased lock through CAS operation and modify the MarkWord to point to itself through CAS operation. If the object needs to be held, modify the MarkWord lock type through the CAS operation to upgrade it to a lightweight lock.
-
Lightweight lock -> Heavyweight lock:
Spinlocks (lightweight locks) introduced in JDK1.4.2 are enabled using -xx :+UseSpinning.
Upgrade to heavyweight lock with more than 10 spins.
In JDK6, it became default and introduced adaptive spin locking (adaptive spin locking).
Adaptive spin lock: Means that the spin time (number of times) is no longer fixed, but is determined by the previous optional time on the same lock and the status of the lock owner. If the spin wait has just successfully acquired the lock on the same lock object, and the thread holding the lock is running, the virtual machine will assume that the spin wait is likely to succeed again, and it will allow the spin wait to last a relatively long time. If spin is rarely successfully acquired for a lock, it is possible to omit the spin process and block the thread directly in future attempts to acquire the lock, avoiding wasting processor resources. (Simply put: decide whether to upgrade the lock based on the probability of success on the lock)