Java object instantiation process

If the content is infringing, please contact to delete, if there is something wrong, please criticize and correct. ?

Introduction

  • The instantiation process of the object is divided into two parts: the loading and initialization of the class, and the initialization of the object
  • To create an object instance of a class, the class needs to be loaded and initialized first, and the class where the main method is located needs to be loaded and initialized first
  • Class initialization is to execute the method, and object instantiation is to execute the method
  • To initialize a subclass, you need to initialize the parent class first

Object instantiation process

When the Java virtual machine encounters a bytecode new instruction, it will first check whether the parameter of this instruction can locate a symbol reference of a class in the constant pool, and check whether the class represented by the symbol reference has been loaded, parsed and initialized. If not, the corresponding class loading process must be performed first.

To give a popular point: JVM encounters class A when executing a certain piece of code, but at this time there is no information about classA in memory, so JVM will go to the corresponding class file to find the class information of classA. And loaded into memory, this is what we call the class loading process. It can be seen that the JVM does not load all classes into memory from the beginning, but only loads it when it encounters a class that needs to be run for the first time, and only loads it once.

Class loading process

Class loading mechanism: If there is no class of the corresponding class, load the class to the method area. Corresponding to loading->verification->preparation->analysis->initialization phase
Load: Load class objects, not necessarily obtained from class files, but can be jar packages, or dynamically generated classes
Verification: Verify whether the class byte stream conforms to the current jvm specification
Prepare: Allocate memory for the class variable and set the variable’s initial value (default value). If it is a final modified object, it is an assignment declaration value
Resolution: Replace the symbolic reference of the constant pool with a direct reference
Initialization: Execute the class constructor (note that it is not an object constructor), assign values to class variables, and execute static code blocks. The jvm will ensure that the of the parent class is executed first before the of the subclass is executed.

● The three parts of verification, preparation and analysis are called connection;
● The <clinit> method is composed of static variable assignment code and static code block; execute class static variable display assignment code first, and then go to static code block code;

When loading a class, the Java virtual machine must do the following three things:

● Get the binary stream of a class by its full name
● Parse the binary data stream of the class into a data structure in the method area (Java class model)
● Create an instance of the java.lang.Class class representing the type. As the access entry of various data of this class in the method area

Conditions that trigger class loading

  • When a new object of a class is created for the first time, it will trigger the loading initialization of the class and the execution of the initialization function of the object, which is instance initialization.

  • When the JVM starts, it will first load and initialize the class containing the main method.

  • Call the static method of the class (such as executing the invokestatic instruction).

  • Perform read and write operations on static fields of classes or interfaces (i.e. execute getstatic, putstatic instructions); except for final modified static fields (already assigned, String and basic types, excluding wrapper types), it is initialized as a compile-time constant quantitative expression.
    Note: When operating a static field, only the class that directly defines this field will be initialized; if the static field defined in the parent class is operated through its subclass, it will only trigger the initialization of the parent class instead of the subclass Initialize

  • When calling the reflection method in JavaAPI (than calling the method (Class.forName) in java.lang.Class, or the method of other classes in the java.lang.reflect package).

  • When a class is initialized, but its parent class is not initialized, it needs to trigger the initialization of the parent class first (interface exception).

Object instantiation process

Memory allocation

When the class loading process is complete, or the class itself has been loaded before, the next step is for the virtual machine to allocate memory for the new object. The memory space required by the object can be completely determined after the class loading process is completed. Allocating memory space for the object is equivalent to dividing a suitable memory from the heap memory. There are two main ways to allocate memory: pointer collision and free list.

Pointer collision: This method divides the heap memory into free space and allocated space, and uses a pointer as the dividing line between the two. When it is necessary to allocate memory space for new objects, it is quite Move the pointer toward the free space for a distance equal to the size of the object. It can be seen that the Java heap memory must be regular in this allocation method, with all free space on one side and allocated space on the other.

Free list: Maintain a list in the virtual machine to record which piece of memory in the heap is free and available. When allocating memory for a new object, look for an available memory block of a suitable size from the list , and update the free list after the allocation is completed. In this way, the free space of the heap memory and the allocated space can be interleaved.

The choice of whether to use pointer collision or free list method to allocate memory is mainly determined by whether the Java heap memory is regular, and whether the Java heap memory is regular depends on the garbage collection algorithm adopted, which involves the garbage collection mechanism.

At the same time, because the action of creating objects is very frequent, there may be multiple threads applying for memory space allocation for objects at the same time. If a certain synchronization mechanism is not adopted at this time, it may cause one thread to modify the pointer in the future. A thread uses the original pointer to allocate memory space, so two solutions are derived: CAS + failure retry, TLAB method.

The first method is easy to understand. Multiple threads use CAS to update the pointer. Under multi-threading, only one thread can update the update, and other threads complete the re-moving of the memory pointer through continuous retry.
The second method is to allocate a piece of memory space in advance for each thread. This memory space is the thread local buffer TLAB. In this way, every time a thread wants to allocate memory, it first goes to the TLAB to obtain it. When the memory space in the TLAB is insufficient, the synchronization mechanism is adopted. Continue to apply for a piece of TLAB space, which reduces the number of applications for synchronization locks.

Initialize zero value

After allocating memory for the object, the virtual machine initializes the allocated memory to zero value, so that the instance variable of the object in Java can be used without initial value, because the code accessed when It is the zero value allocated by the virtual machine for this memory.

Set object header

The object header is like our human ID card, which stores some data that identifies the object, that is, some metadata of the object. Let’s first look at the composition of the object.

After the zero value is initialized, how to know which class instance the object is, it is necessary to set the pointer to the type information in the method area, and the setting of the relevant information in the object Mark Word is completed at this stage.

Instance object initialization

The object instantiation process is actually to execute the class constructor corresponding to the () method in the bytecode file (called the instance constructor); the () method consists of non-static variables, non-static code blocks and corresponding constructors
The () method can be overloaded multiple times, and there are several () methods in the class with several constructors
The code execution sequence in the () method is: parent class variable initialization, parent class code block, parent class constructor, subclass variable initialization, subclass code block, subclass constructor.
Static variables, static code blocks, ordinary variables, ordinary code blocks, execution order of constructors

The order of instantiation of a child class with a parent class is as follows

Class loaders and parental delegation rules, how to break parental delegation rules

● class loader
○ Obtain the binary byte stream describing this class through the fully qualified name of a class. The code module that implements this action is called a class loader
○ Any class needs its loader and the class itself to determine the uniqueness of the class in the JVM; each class loader has its own class namespace, and the same class class is loaded by different loaders, and it is judged by the JVM as different classes

● Parental delegation model
○ The boot class loader is implemented in C++ code and is part of the virtual machine. Responsible for loading the class library under lib
○ Other class loaders are implemented in java language, independent of JVM, and inherit ClassLoader
○ extent ClassLoader is responsible for loading the class libraries under the libext directory
○ application ClassLoader is responsible for loading the code under the user path (ClassPath)
○ Loading the same class file by different class loaders will result in two classes. The solution given by java is that the lower-level loader entrusts the upper-level loader to load the class. If the parent class cannot be loaded (the corresponding class cannot be found in the directory it is responsible for), it will be handed over to the lower-level class loader to load. As shown below

● Break the parental delegation model
○ The parent delegation model is not a mandatory constraint model, but a class loading implementation method recommended by java designers to developers
○ The parental delegation model solves the same problem of loading base classes for each class very well (the more basic classes are loaded by the upper-level loader), but the base class is always used as an API called by user code, but if its specific implementation is the lower-level The code of the base class needs to call the code of the lower layer at this time, so the parental delegation model needs to be broken
○ Such as JNDI service, the JNDI code has a startup class to load (rt.jar), which needs to call the JNDI SPI (Service Provider Interface) code deployed by an independent vendor under the application classpath. In order to solve the problem of SPI code loading, java introduces a thread context class loader to load SPI code. That is, the parent class loader requests the subclass to complete the loading action of the class
○ The thread context class loader, which will be inherited from the parent thread when the thread is created, if the global scope has not been set, the default setting is application Class Loader

Complete process (reference)

The whole process of Java object instantiation