Java object header
Have you ever wondered what java objects look like from the inside?
Under the cat there will be a detailed description of the java object header, what it consists of and how much memory it takes.
To begin with, recall that in jvm any object in memory consists of the object header and object variables (links and primitives). Also, the final size of the object can be expanded to become a multiple of 8 bytes.
The title of each object (except for the array) consists of two machine words - mark word and class word . Arrays have an additional 32 bits to describe the length of the array.
The Mark word stored identity hashcode, the bits used by the garbage collector and the bits used for the locks. You can always find more details in the corresponding OpenJDK sorts markOop.hpp .
A class word stores a pointer to the class itself, that is, to the place where the information about this data type lies: methods, annotations, inheritance, and more. More details can also always be found in the corresponding OpenJDK sorts of klass.hpp .
Let's now take a closer look at the title of the object, and in particular mark word
32 bit jvm
As you can see from the table, the content of Mark word can vary greatly depending on the current state of the object.
Normal state of the object (biased_lock = 0, lock = 01)
- identity_hashcode is the hash of an object that appears lazily. If the object has a System.identityHashCode (obj) call for the first time, then this hash will be calculated and written to the object header.
In other states, when various streams compete for an object, identity_hashcode will be stored not in the object header, but in the object’s monitor.
- age - the number of garbage collections experienced. When age reaches the number of max-tenuring-threshold, the
object moves to the hip area of the old generation.
- biased_lock - contains 1 if biased locking is enabled for this object, otherwise 0.
When Biased Locking is turned on, the object moves as it were to the first object that captured its monitor. Subsequent capture of the object in the same stream will be slightly faster.
Here are the basic theoretical prerequisites for this lock:
- Throughout the life of the object, it is predominantly owned by one
- If the thread recently used a lock on this object, most likely the processor cache will still contain the data that will be needed to re-capture this object.
Biased Locking is enabled by default since java 6, -XX: -UseBiasedLocking
- lock - contains the lock status code. 00 - Lightweight Locked, 01 - Unlocked or Biased, 10 - Heavyweight Locked, 11 - Marked for Garbage Collection.
That is, in the table, the state of an object is determined by the combination of the biased_lock and lock bits.
Biased Locked mode (biased_lock = 1, lock = 01)
- thread - in biased locking mode, it is assumed that the object is predominantly owned by a particular thread, the id of this thread is stored in the field.
- epoch contains some temporary indicator of ownership of the object by a thread whose id is stored in thread
Lightweight Locked Mode (lock = 00)
In this mode, it is assumed that the capture time by this object by different flows does not intersect at all or does not overlap insignificantly. In this mode, instead of heavy blocking the operating system, the JVM uses atomics.
- ptr_to_lock_record - CAS (compare and set) inside the spin loop is used to set / wait for a lock.
For reference, the minimum OS blocking time will be in the region of about 10 ms, with the help of atomics, the stream does not fall asleep, but continues to thresh a small cycle, and as soon as the resource is free, the atomic cycle will end and the stream will immediately capture this object.
Heavyweight Locked Mode (lock = 10)
- ptr_to_heavyweight_monitor - if the capture time of this object with different streams will overlap significantly, then the lightweight lock will be replaced with a heavyweight lock. A pointer to the monitor will be written to ptr_to_heavyweight_monitor. OS lock is used.
So in 32 bit jvm the header of the object consists of 8 bytes. Arrays additionally have 4 bytes.
64 bit jvm
On a 64 bit jvm, the object header consists of 16 bytes. Arrays additionally have 4 bytes.
64 bit jvm with pointer compression
An object header consists of 12 bytes. Arrays additionally have 4 bytes.
A little bit about pointer compression. For a 32-bit pointer, the address space is limited to 4GB. However, if we recall again that in jvm the size of an object is a multiple of 8 bytes, then we can use a pseudo 35-bit pointer, with three zeros at the end. And, thus, refer already to 32GB of memory. Compression is not free, the price is an additional operation (pointer << 3) for any call to heap.
Link to the original article:
I would also like to add that everything described here is not a dogma, perhaps in other versions of jvm the title of the object will be different. Described here is relevant for openjdk 8.