In the last article, we started with HotSpot’s source code and introduced the Java object model. This article builds on the previous article and introduces Java object headers. Mainly introduced the role of the object head, structure and his relationship with the lock.

Java Object Model review and errata

In the previous article, the object header was incorrectly described, which I have corrected in my blog post. So let me rephrase that.

For each Java class, when it is loaded by the JVM, the JVM creates an instanceKlass for that class, which is stored in the methods area and used to represent the Java class at the JVM layer. When we create an object using new in Java code, the JVM creates an instanceOopDesc object that contains the object header and instance data.

What is this object header?

class oopDesc {
  friend class VMStructs;
 private:
  volatile markOop  _mark;
  union _metadata {
    wideKlassOop    _klass;
    narrowOop       _compressed_klass;
  } _metadata;
}
Copy the code

The _mark and _metadata in the above code are simply definitions of object headers. _metadata has been introduced before and will not be covered here. Since this topic focuses on JAVA concurrency, this article expands on _mark, or Mark Word.

Object header information is an additional storage cost unrelated to the data defined by the object itself. Considering the space efficiency of the virtual machine, Mark Word is designed as a non-fixed data structure to store as much information as possible in a very small space. It will reuse its storage space according to the state of the object.

The design of Markword is very similar to that of the network protocol packet header: Mark Word is divided into multiple bits and bits are given different meanings in different object states. The following figure describes the meanings of the mark Word bits in different object states on a 32-bit virtual machine.

Also, in the HotSpot source code we can find the definition of the object header object, which will confirm the above description. Corresponds to the markOop. HPP class.

enum { age_bits                 = 4,
      lock_bits                = 2,
      biased_lock_bits         = 1,
      max_hash_bits            = BitsPerWord - age_bits - lock_bits - biased_lock_bits,
      hash_bits                = max_hash_bits > 31 ? 31 : max_hash_bits,
      cms_bits                 = LP64_ONLY(1) NOT_LP64(0),
      epoch_bits               = 2
};
Copy the code

As you can see from the above enumeration definition, the object header mainly contains information about GC generation age, lock status markers, hash codes, epoch, and so on.

As you can see from the figure above, there are five types of object states: lockless, lightweight, heavyweight, GC tag, and biased lock. In a 32-bit virtual machine, two Bits are used to store the lock marked as, but as we know, two Bits can represent a maximum of four states: 00, 01, 10, and 11.

In the 32-bit HotSpot virtual machine where the object is not locked, 25Bits of the Mark Word’s 32 Bits space are used to store the object HashCode, 4Bits are used to store the object generation age, 2Bits are used to store the lock flag bit, and 1Bit is fixed to 0. Represents a non-biased lock.

The markOop. HPP class has a definition of object state:

  enum { locked_value             = 0,
         unlocked_value           = 1,
         monitor_value            = 2,
         marked_value             = 3,
         biased_lock_pattern      = 5
  };
Copy the code

A brief translation:

locked_value(00) = 0

unlocked_value(01) = 1

monitor_value(10) = 2

marked_value(11) = 3

biased_lock_pattern(101) = 5

As to why so many states are defined, the above mentioned lightweight locks, heavyweight locks, biased locks and their previous relationships will be highlighted in the next article, so stay tuned.