The virtual machine loads the data describing the Class from the Class file to the memory, verifies, transforms, and initializes the data, and finally forms Java types that can be directly used by virtual machines. This is the Class loading mechanism of virtual machines. The dynamic loading and linking of Java runtime makes Java an inherently dynamic extension language.

The timing of class loading

The entire life cycle of a class from the moment it is loaded into vm memory to the moment it is unloaded from memory includes:

  • Loading

  • Verification

  • Preparation

  • Resolution

  • Initialization

  • Using

  • 2. Unloading is a class.

The sequence of the seven stages is shown below:

The five phases of load, validation, preparation, initialization, and unloading are in a definite order, and the loading process of a class must begin in this order, while the parsing phase may not, in some cases, begin after the initialization phase, in order to support runtime binding in the Java language.

The Java Virtual Machine specification specifies that there are only five cases in which classes must be “initialized” immediately, and loading, validation, and preparation naturally need to begin before that. The five cases are:

  1. When you encounter four bytecode instructions — New, getstatic, putstatic, or Invokestatic — you need to trigger initialization if the class has not already been initialized.

  2. When you use the java.lang.Reflect method to make a reflection call to a class, you need to trigger initialization if the class is not already initialized.

  3. When initializing a class, if the parent class has not been initialized, the initialization of the parent class must be triggered first.

  4. When a VM starts, the user needs to specify a primary class to execute. The VM initializes this class first.

  5. When using JDK1.7 dynamic language support, if a Java lang. Invoke. The final analytical results REF_getStatic MethodHandle instance, REF_inkokeStatic, REF_putStatic method handles, If the class to which the method handle corresponds has not been initialized, it needs to be initialized first.

The behavior in the above five scenarios is called making an active reference to a class. In addition, all ways of referring to a class do not trigger initialization, called passive references. Examples of passive quotes:

  • Referring to a static field of a parent class by subclass does not cause subclass initialization;

  • Referencing a class through an array definition does not trigger initialization of the class;

  • Constants are stored in the constant pool of the calling class at compile time and are not directly referenced to the class that defines them, so they do not trigger initialization of the class that defines them.

Interfaces and classes before the difference between article 5 of the “one and only” need to start the initialization in the scene 3 kinds, when a class is initialized, require all of its parent class has been initialized, but when an interface is initialized, does not require all of its parent interface has completed initialization, only at the time of real use to the parent interface, will be initialized.

The process of class loading

The class loading process consists of five phases: load, validate, prepare, parse, and initialize.

loading

“Loading” is just one phase of the “class loading” process. During the load phase, the virtual machine needs to do three things:

  1. Get the binary byte stream that defines a class by its fully qualified name;

  2. Convert the static storage structure represented by this byte stream to the runtime data structure of the method area;

  3. Generate a java.lang.Class object in memory that represents the Class and acts as an access point for the Class’s various data in the method area.

validation

Validation is the first step in the connection phase. The purpose of this step is to ensure that the byte stream contained in the Class file meets the requirements of the current virtual machine and does not compromise the security of the virtual machine itself. On the whole, the verification stage can be roughly divided into four verification actions: file format verification, metadata verification, bytecode verification, symbol reference verification.

File format validation

Verify that the byte stream complies with the Class file format specification and can be processed by the current version of the virtual machine. The main purpose of file format validation is to ensure that the input byte stream is properly parsed and stored in the method area in a format that describes the information of a Java type. Possible verification points:

  • Whether it starts with a magic number 0xCAFEBABE;

  • Check whether the major and minor versions are within the range processed by the current VM.

  • Whether the constants in the constant pool have unsupported constant types;

  • Whether various index values that point to constants point to nonexistent constants or nonconforming constants;

  • CONSTANT_Utf8_info whether the constant does not conform to UTF8 encoding data;

  • Whether any other information has been deleted or added to parts of the Class file and the file itself.

Metadata validation

The information described by bytecode is semantic analyzed to ensure that the information described conforms to the requirements of Java language specification. Possible verification points:

  • Whether this class has a parent (all classes except java.lang.Object should have a parent);

  • Whether the parent of this class inherits classes that are not allowed to be inherited (classes modified by final);

  • If the class is not abstract, whether it implements all methods required by its parent class or interface;

  • Whether a field or method ina class conflicts with the parent class (for example, overwriting a final field in the parent class, or overloading a method that does not conform to the rules, such as the same method parameters but different return value types).

Bytecode verification

Bytecode verification is the most complex step in the whole validation process. The main purpose is to determine that the program semantics are legitimate and logical through data flow and control flow analysis. Possible verification points:

  • Ensure that the data type of any real operand stack and the sequence of instruction codes work together. For example, do not place an int in the operand stack, but load it into the local variable table as long.

  • Ensure that jump instructions do not jump to bytecode instructions outside the method body;

  • It is safe to ensure that type conversions are valid in the method body. For example, it is safe to assign a subclass object to a superclass data type, but it is dangerous and illegal to assign a superclass object to a subtype, or even to an unrelated data type that has no inheritance relationship.

Symbolic reference verification

The verification of this step occurs when the virtual machine converts symbolic references to direct references, which takes place during the third phase of the join, called parsing. Notation to refer to the main purpose of the validation is to ensure that the parsing action can normal operation, if not through reference symbol verification, so will be thrown a Java lang. A subclass of IncompatibleClassChangeError anomalies, such as: Java. Lang. IllegalAccessError, Java. Lang. NoSuchFieldError, Java. Lang. NoSuchMethodError, etc. Possible verification points:

  • Whether the corresponding class can be found for fully qualified names described by strings in symbolic references;

  • Whether field descriptors that match methods and methods and fields described by simple names exist in the specified class;

  • The accessibility of classes, fields, and methods in symbolic references is accessible to the current class.

To prepare

The preparation phase is the phase where memory is formally allocated for class variables and initial values are set. The memory used by these variables is allocated in the method area. Memory allocation during the preparation phase includes only class variables, not instance variables, which will be allocated in the Java heap along with the object when it is instantiated. The initial value for the preparation phase, which “normally” is zero for the data type.

parsing

The parsing phase is the process by which the virtual machine replaces symbolic references in the constant pool with direct references.

  • Symbolic reference: A symbolic reference describes the referenced object as a set of symbols, which can be any literal, as long as it is used to unambiguously locate the object. Symbolic references are independent of the memory layout of the virtual machine implementation, and the target of the reference does not necessarily have been loaded into memory.

  • Direct reference: A direct reference can be a pointer directly to the target, relative to an offset, or a handle that can be indirectly located to the target. A direct reference is related to the memory layout implemented by the VIRTUAL machine. The translation of a symbolic reference on different virtual machine instances will not be the same. If there is a direct reference, the target of the reference must already exist in memory.

The parse action is mainly for class or interface, field, class method, interface method, method type, method handle, and call point qualifier.

Initialize the

The initialization phase is the process of executing the class constructor () method. () Some characteristics and details of method execution that may affect program execution behavior:

  • Is the method by the compiler automatically collect all kinds of variable assignment in class action and static blocks the statement in the combined, produced by the compiler to collect the order by the order of the statement in the source file is determined by, static block can only access to the definition in the static block variables before, after its variables, static block in the previous assignment, But it cannot be accessed.

  • Unlike the class constructor, this method does not explicitly call the superclass constructor, and the virtual machine guarantees that the () method of the superclass is executed before the () method of the subclass is executed. So the first class of the () method to be executed in the virtual machine must be java.lang.object.

  • Since the () method of the parent class executes first, it means that static blocks defined in the parent class take precedence over assignment operations in the child class.

  • This method is not necessary for a class or interface. If a class has no static block and no assignment to a variable, the compiler may not generate () methods for that class.

  • Static blocks cannot be used in interfaces, but there are still assignment operations that initialize variables, so interface classes generate () methods as well as classes. But unlike a class, the () method of an interface does not need to execute the () method of the parent interface first. The parent interface is initialized only when a variable defined in the interface is used. In addition, the implementation class of the interface does not execute the interface’s () method when initialized.

  • The virtual machine ensures that a class’s () method is properly chained and synchronized in a multithreaded environment. If multiple threads initialize a class at the same time, only one thread will execute the class’s () method, and all the other threads will block and wait until the active thread finishes executing the () method. If you have a long operation in a class-based () method, multiple processes can block.

Class loader

Implement the class-loading action of “get the byte stream describing the class by a fully qualified name” outside the Java virtual machine so that the application can decide how to get the classes it needs. The code module that implements this action is called a class loader.

For any class, the uniqueness of the Java virtual machine needs to be established both by the class loader that loads it and by the class itself. Each class loader has a separate class namespace. That is, comparing two classes is only meaningful if the two classes are loaded by the same Class loader. Otherwise, even if the two classes come from the same Class file and are loaded by the same VIRTUAL machine, as long as they are loaded by different Class loaders, the two classes must be different.

Parental delegation model

From the perspective of the Java virtual machine, there are only two different class loaders: the launch class loader, which is implemented in C++ and is part of the virtual machine itself; The other is all the other classloaders that have Java language implementations, are independent of the virtual machine, and all inherit from the abstract java.lang.classloader class.

From a developer’s perspective, most Java programs use one of three system-provided classloaders:

  • ** This class loader is responsible for storing it in the <JAVA_HOME>/lib directory, or in the path specified by the -xbootCLASspath parameter, and is a library that the VIRTUAL machine recognizes by filename (e.g. Rt.jar, which will not be loaded even if it is placed in the lib directory. The boot class loader cannot be directly referenced by Java programs. If you need to delegate the loading request to the boot class loader when writing a custom class loader, you can use NULL instead.

  • ** Extended class loaders: ** This loader is implemented by sun.misc.Launcher$ExtClassLoader and is responsible for loading all libraries in the <JAVA_HOME>/lib/ext directory, or in the path specified by the java.ext.dirs system variable. Developers can use the extended classloader directly.

  • ** Application class loader: ** This loader is implemented by sun.misc.Launcher$AppClassLoader. Since this ClassLoader is the return value of the getSystemClassLoader() method in ClassLoader, it is also commonly referred to as the system ClassLoader. It is responsible for loading libraries specified on the user’s classpath. Developers can use this class loader directly. If the application does not have its own custom class loader, this is generally the default class loader in the application.

The relationship before class loaders is generally shown as follows:

The hierarchical relationship between class loaders shown in the figure above is called the parent delegate model of class loaders. The parent delegate model requires that all class loaders have their own parent class loaders, except for the top-level start class loaders.

The working process of the parental delegation model is: If a class loader received the request of the class loading, it won’t try to load the first class, but to delegate the request to the parent class loader to complete, each level of class loaders, so all the load request should be sent to the top finally start the class loader, only when the parent class loader feedback they can’t finish the load request, The child loader will try to load it itself.

One of the obvious benefits of using the parent-delegate model to organize relationships between class loaders is that Java classes have a hierarchical relationship with priority along with their classloaders.