[Java][JVM] Object creation and OOP-Klass model

1. Object creation

The creation of an object is usually through a new object. When the virtual machine receives a new command, it will do the following operations. 
(1) Determine whether the class corresponding to the object is loaded, linked, initialized. When the 
virtual machine receives a new instruction, it will first check whether the specified parameter can locate a symbolic reference of a class in the constant pool, and check the symbolic reference Whether the represented class has been loaded, linked and initialized by the class loader. If not, perform the corresponding class loading process first. We have already mentioned the class loader in the previous article, so I won't repeat it here.

(2) Allocate memory for the object 
After the class has been loaded, it will then divide a block of memory in the Java heap and allocate it to the object. There are two ways to allocate memory according to whether the Java heap is regular:

  • Pointer collision: If the memory of the Java heap is regular, that is, all the used memory is placed on one side, and the free memory is placed on the other side. When allocating memory, move the pointer in the middle to the free memory by a distance equal to the size of the object, so that the memory allocation is completed.
  • Free list: If the memory of the Java heap is not regular, you need to maintain a list by the virtual machine to record which memory is available, so that you can query the list from the list when it is allocated to the object and allocate it Update the list record afterwards.

Whether the memory of the Java heap is regular or not depends on whether the collector is used and whether the collector has a compression function. The garbage collector will be introduced in a later article in this series.

(3) Dealing with concurrency security issues 
Creating objects is a very frequent operation, so concurrency issues need to be solved in two ways:

  • Synchronize the action of allocating memory space, such as using the CAS algorithm in the virtual machine and matching the failure retry method to ensure the atomicity of the update operation.
  • Each thread pre-allocates a small piece of memory in the Java heap. This memory is called Thread Local Allocation Buffer (Thread Local Allocation Buffer) abbreviated as TLAB. When a thread needs to allocate memory, it allocates memory on the TLAB of the corresponding thread. When the TLAB in the thread is used up and is allocated to a new TLAB, synchronization lock is needed at this time. Use the -XX:+/-UserTLAB parameter to set whether the virtual machine uses TLAB.

(4) Initialize the allocated memory space and 
the allocated memory, except for the object header, are initialized to zero.

(5) Set the object header of 
the object. Store the data such as the class of the object, the HashCode of the object, and the GC generation age of the object in the object header of the object.

(6) Execute the init method for initialization. 
Execute the init method, initialize the member variables of the object, and call the construction method of the class, so that an object is created.

2. Heap memory layout of the object

The object is created, and memory has been allocated in the Java heap, so how is the object laid out in the heap memory? 
Taking the HotSpot virtual machine as an example, the layout of the object in the heap memory is divided into three areas, namely, the object header (Header), the instance data (Instance Data), and the alignment padding (Padding).

  • Object header: The object header includes two parts of information, namely Mark World and metadata pointer. Mark World is used to store the data of the object at runtime, such as HashCode, lock status flag, GC generation age, etc. The metadata pointer is used to point to the type information of the target class in the method area, and the specific type of the object can be determined through the metadata pointer.
  • Instance data: used to store various types of field information in the object (including those inherited from the parent class).
  • Alignment padding: Alignment padding does not necessarily exist, it acts as a placeholder and has no special meaning.

The memory layout of the object is shown in the figure below. 
Heap memory layout.png

3. HotSpot's object model

HotSpot uses the OOP-Klass model, which is a model used to describe Java object instances. OOP (Ordinary Object Pointer) refers to ordinary object pointers, while Klass is used to describe the specific types of object instances. 
In HotSpot, instanceOopDesc ​​and arrayOopDesc ​​are used to describe the object header, and the arrayOopDesc ​​object is used to describe the array type. 
The code of instanceOopDesc ​​is shown below. 
openjdk/hotspot/src/share/vm/oops/instanceOop.hpp

Copy code

class instanceOopDesc : public oopDesc {
 public:
  // aligned header size.
  static int header_size() { return sizeof(instanceOopDesc)/HeapWordSize; }

  // If compressed, the offset of the fields of the instance may not be aligned.
  static int base_offset_in_bytes() {
    // offset computation code breaks if UseCompressedClassPointers
    // only is true
    return (UseCompressedOops && UseCompressedClassPointers) ?
             klass_gap_offset_in_bytes() :
             sizeof(instanceOopDesc);
  }

  static bool contains_field_offset(int offset, int nonstatic_field_size) {
    int base_in_bytes = base_offset_in_bytes();
    return (offset >= base_in_bytes &&
            (offset-base_in_bytes) < nonstatic_field_size * heapOopSize);
  }
};

Copy code

It can be seen that instanceOopDesc ​​inherits from oopDesc: 
openjdk/hotspot/src/share/vm/oops/oop.hpp

Copy code

class oopDesc {
  friend class VMStructs;
 private:
  volatile markOop  _mark;
  union _metadata {
    Klass*      _klass;
    narrowKlass _compressed_klass;
  } _metadata;

  // Fast access to barrier set.  Must be initialized.
  static BarrierSet* _bs;
...
}

Copy code

oopDesc ​​contains two data members: _mark and _metadata. The _mark object of type markOop refers to the Mark World mentioned earlier. _metadata is a union, where _klass is an ordinary pointer and _compressed_klass is a compressed class pointer. They are the metadata pointers mentioned above. Both pointers point to the instanceKlass object, which is used to describe the specific type of the object. 
The code of instanceKlass is shown below. 
openjdk/hotspot/src/share/vm/oops/instanceKlass.hpp

Copy code

class InstanceKlass: public Klass {
  ...
  enum ClassState {
    allocated,                          // allocated (but not yet linked)
    loaded,                             // loaded and inserted in class hierarchy (but not linked yet)
    linked,                             // successfully linked/verified (but not initialized yet)
    being_initialized,                  // currently running class initializer
    fully_initialized,                  // initialized (successfull final state)
    initialization_error                // error happened during initialization
  };
  ...
 } 

Copy code

instanceKlass inherits from Klass, and the enumeration ClassState is used to identify the loading progress of the object. 
Knowing the OOP-Klass model, we can analyze how the Java virtual machine finds the corresponding object instance through the object reference in the stack frame, as shown in the following figure. 
OOP-Klass model(1).png

It can be seen from the figure that the instanceOopDesc ​​object in the Java heap is found through the object reference in the stack frame, and the instanceKlass in the method area is found through the metadata pointer in the instanceOopDesc ​​to determine the specific type of the object.

 

 

Guess you like

Origin blog.csdn.net/xfb1989/article/details/110050492