The process of the JVM loading the data from the class file into memory, validating the data, parsing and initializing it, and finally forming the Java type that the JVM can use directly is the class loading mechanism .
1.
time of class loading
Class starts from being loaded into the virtual machine's memory, and its lifecycle includes: Load (Loading), validate (verification), prepare (preparation), Parse (Resolution), Initialize ( initialization), use (using), unload (unloading) seven phases, in which the validation, preparation, and resolution of three parts are collectively referred to as connections. The order is as follows:
Load (mount), validate, prepare, initialize, and unload the five stage sequence is fixed, and the class's loading process must begin in this order, while the parsing phase is not necessarily; it can be started after initialization in some cases, for runtime dynamic binding attributes. It is important to note that these phases are usually mixed with each other, usually invoking or activating another phase during one phase of execution.
When to start the first phase of the class loading process: load. There is no mandatory constraint in the virtual machine specification, which can be given to the specific implementation of the virtual machine from the grasp. However, for the initialization phase, the virtual machine is strictly defined and there are only four cases where the class must be initialized immediately (while loading, validating, and preparing the natural need to start before this):
- When instantiating an object using the New keyword. The time to read or set a static field for a class (except for a static field that was final decorated, has put the result in a constant pool at compile time), and a static method that invokes a ray.
- When you make a reflection call to a class, you need to trigger its initialization first if you are tired without initialization.
- When a class is initialized, it is found that its parent class has not yet been initialized, and the initialization of its parent class needs to be triggered first.
- When the virtual machine starts, the user needs to specify a main class to execute (the class that contains the method of main (), which initializes the main class first.
For those four scenarios that trigger the class to initialize, a strong class qualifier is used in the virtual machine specification: "Have and only", and the behavior in these four scenarios is referred to as a class for active reference. All other ways of referencing a class do not trigger initialization, which is called a passive reference. Here are three examples to illustrate a passive reference:
- For a static field, only the class that directly defines the field is initialized, so by referencing the static field defined in the parent class by its subclass, only the initialization of the parent class is triggered and not the start. Whether to trigger the loading and validation of subclasses depends on the specific implementation of the virtual machine.
Packageorg.fenixsoft.classloading;/** * Passive use class field demo one: * Referencing a static field of a parent class through a subclass does not cause subclasses to initialize **/ Public class superclass { Static{System.out.println ("Superclass init!"); } Public Static intValue =123;} Public class subclass extends superclass { Static{System.out.println ("Subclass init!"); }}/** * Non-active Use class field demo **/ Public class notinitialization { Public Static void Main(string[] args) {System.out.println (subclass.value); }} Run Result: Superclass init!123
- The reference class is defined by an array and does not trigger initialization of this class, but this code triggers the initialization phase of another class named "[Lorg.fenixsoft.classloading.SuperClass", which is not a valid class name for user code. He is a subclass that is automatically generated by a virtual machine and inherits directly from Java.lang.Object, and the creation action is triggered by the bytecode directive NewArray. This class represents a one-dimensional array with an element type of org.fenixsoft.classloading.SuperClass, the attributes and methods that are expected in the array (only the Length property and clone () that the user can directly use to be modified to public Methods) are implemented in this class. This class wraps the access method of the array element (to be exact, the bounds check is not encapsulated in the class accessed by the array element, but is encapsulated in the Xload, xastore bytecode directive of the array access). Checks to throw an Arrayindexoutofboundexception exception when an array is out of bounds.
package org.fenixsoft.classloading;/** * 被动使用类字段演示二:* 通过数组定义来引用类,不会触发此类的初始化 **/publicclass NotInitialization { publicstaticvoidmain(String[] args) { new SuperClass[10]; }}
- Constants are stored in the constant pool of the calling class at compile time and are not inherently referenced directly to classes that define constants, so initialization of classes that define constants is not triggered.
Packageorg.fenixsoft.classloading;/** * Passive use class field demo three: * Constants are stored in the constant pool of the calling class at compile time and are not inherently referenced directly to the class that defines the constants, so the initialization of the class defining the constants is not triggered. **/ Public class constclass { Static{System.out.println ("Constclass init!"); } Public Static FinalString HELLOWORLD ="Hello World";}/** * Non-active Use class field demo **/ Public class notinitialization { Public Static void Main(string[] args) {System.out.println (Constclass.helloworld); }} Run Result: Hello World
- The loading process of an interface is slightly different from the loading process of a class:
- The static{} statement block cannot be used in the interface, but the compile time will still generate the class constructor for the interface, which initializes the interface to the dirty, well defined member variable.
- The main difference is the third in the initialization scenario: When an interface is initialized, it does not require all of its parent interface to be initialized, only when it is actually used to the parent class interface, such as constants defined in the reference interface.
2.
class Loading Process
- Loading
During the load-loading phase of the class, the virtual machine needs to complete the following three things:
1) a binary byte stream that defines this class is obtained through the fully qualified name of a class.
2) Convert the static storage structure represented by this byte stream into the runtime data structure of the method area.
3) Generate a Java.lang.Class object representing this class in the Java heap as the access entry for the data in the method area.
Obtaining a binary stream that defines this class through the fully qualified name of a class does not indicate that the binary byte stream is to be fetched from a class file, and that exactly does not indicate where to get and how to get it. In contrast to other stages of the class loading process, the binary stream of the fetch class during the load phase is the most controllable phase of the development period, because the load phase can be done either by using the system-provided ClassLoader, or by a user-defined class loader. The load phase and parts of the connection phase (such as validation actions in a subset of bytecode file formats) are interleaved, the loading phase is not complete, the connection phase may have begun, but the actions of these clips during loading are still part of the connection phase, and the two phases remain in a fixed order.
Validation
Validation is the first step in the connection phase to ensure that the information contained in the byte stream of the class file conforms to the requirements of the current virtual machine and does not compromise the security of the virtual machine itself. The workload for this phase accounts for a significant portion of the virtual machine's class loading subsystem. The following four phases of the inspection process are roughly completed: file format validation, metadata validation, bytecode validation, and symbol reference validation.
- File format validation: Verifies that the byte stream conforms to the specification of the class file format and can be processed by the current virtual machine. It mainly includes the following verification points:
- Whether to start with the magic number 0xcafebabe.
- Whether the primary and secondary version number is within the current Virtual machine processing range
- Constant type is not supported in constant pool constants (check constant tag flag)
- Whether there are constant or non-conforming types in various index values that point to constants
- ......
- This phase of validation is based on the byte stream , after this phase of validation, the byte stream will go into the memory of the method area for storage, so the following three verification is based on the storage structure of the method area .
- Meta-data validation
is the semantic analysis of the information of bytecode description, in order to ensure that the information described is in accordance with the requirements of the Java language Specification, is to verify the data types in the metadata information. The following validations may be included:
- Whether this class has a parent class (except for object, all classes should have a parent class)
- Whether this class inherits a class that is not allowed to be inherited (a class that is final decorated)
- If this class is not an abstract class, does it implement all of the methods that are required to be implemented in its parent class or interface.
- The field in the class, whether the method is inconsistent with the parent class (such as the final method that overrides the parent class).
- BYTE code Verification
Is the most complex phase of the entire validation process, primarily for data flow and control flow analysis. A validation analysis of the method body of a class ensures that the class's methods do not behave in a way that harms the virtual machine at run time:
- Ensure that any time the data type of the operand stack and the instruction code sequence can work together, there will be no such situation: an int type of data is placed in the Operation Stack, and is loaded as a long type in the local variable table when used.
- Ensure that the jump instruction does not jump to a bytecode directive other than the method body.
- Ensures that the type conversions in the method body are valid.
- ......
- If the bytecode of a class method body is not verified by itself, it must be problematic, but if you pass the bytecode verification, it does not mean that it must be safe.
- Symbol Reference Validation
Occurs when a virtual machine converts a symbolic reference to a direct reference, and this conversion action occurs during the third phase of the connection – the parsing phase. Symbolic reference validation can be seen as a matching check of information outside the class itself (the various symbol references in a constant pool) to ensure that parsing is performed normally. There are usually a few things to consider:
- The fully qualified name that is described by a string in the symbol reference can find the corresponding class.
- Specifies whether the method and field described by the field descriptor and simple name of the method are present in the specified class.
- Whether the accessibility of classes, fields, and methods in a symbol reference can be accessed by the current class.
- ......
- The validation phase is not necessarily a necessary phase, and if all the code that is running has been reused and validated, you can consider using the-xverfify:none parameter to turn off most of the class validation measures during the implementation phase to shorten the class load time for the virtual machine.
Prepare
is a phase that formally allocates memory for class variables and sets the initial value of class variables, which are allocated in the method area. Note two points:
- In this case, the memory allocation includes only class variables (static modified variables), not instance variables, and instance variables are allocated in the Java heap along with the object when the object is instantiated.
- The initial value described here is usually the value of 0 of the data. Suppose you define a class variable:
public static int value = 123;
Then the initial value of the variable value after the preparation phase is 0, not 123, because this time does not start to execute any Java method, and the value is assigned to 123 putstatic instruction is the program after compiling, stored in the class constructor method, So an action that assigns value to 123 will not be executed until the initialization stage.
If the Constantvalue attribute exists in the field property sheet of a class field, it is initialized to the value specified by the Constantvalue property in the prepare phase. Assume:
public static final int value = 123;
Compile-time Javac will generate the constant property for value, and in the prepare phase the virtual machine will assign value to 123 based on the settings of Constantvalue.
parsing
is the process by which a virtual machine replaces a symbolic reference within a constant pool with a direct reference.
- Symbol Reference: A symbol reference is a set of symbols to describe the referenced target, the symbol can make any form of the literal, as long as the use is able to locate the target without ambiguity. The symbol reference is independent of the memory layout implemented by the virtual machine, and the referenced target is not necessarily already loaded into memory.
- Direct reference: Can be a pointer directly to the target, a relative offset, or a handle that can be indirectly anchored to the target. Direct references are related to the memory layout implemented by the virtual machine, and direct direct references that are translated directly from the same symbol reference on different virtual machine instances will generally not be the same. If there is a direct reference, the referenced target must already exist in memory.
The exact time of the parsing phase is only required in the execution of Anewarray, Checkcat, GetField, Getstatic, instanceof, Invokeinterface, invokespcial, Invoketatic, Invokecirtual, Multianewarray, New, Putfield, and putstatic are the 13 byte-code directives used to manipulate symbol references before parsing the symbol references that they use.
Parsing actions are mainly for classes or interfaces, fields, class methods, interface methods, and four types of symbolic references.
Parsing of classes or interfaces
Assuming that the current code is in the Class D, if you want to parse a never-parsed symbol reference n into a direct reference to a class or interface C, the complete parsing process for the virtual machine needs to include the following 3 steps:
1) If C is not an array type, the virtual machine will pass the permission named N to the class loader of D to load the Class C. During the loading process, due to metadata validation and bytecode validation, it is possible to trigger loading actions for other related classes, such as loading the class's parent class or implementing an interface. Once any exception occurs, the declaration fails.
2) If C is an array type, and the element type of the array is an object, that is, the N descriptor will resemble "[Ljava.lang.Integer", the array element type will be loaded according to the 1th rule. If the descriptor of N is a previously assumed form, the element type that needs to be loaded is "Java.lang.Integer", and then the virtual machine generates an array object representing this array dimension and element.
3) If there are no exceptions to the above steps, then C is actually referred to as a valid class or interface in the virtual machine, but before parsing is complete, a symbolic reference validation is made to confirm that C has access to D. If you find that you do not have access rights, you will throw a Illegalaccesserror exception.
Field resolution
The Constant_class_info symbol reference for the index in the Class_index item in the field table will be parsed first, that is, the symbol reference of the class or interface to which the field belongs. If any exception occurs during the parsing of a class or interface symbol reference, it causes the field symbol reference resolution to fail. If the resolution is successful, the class or interface to which this field belongs is represented in C, and the virtual machine specification requires the following steps to search for C in subsequent fields:
1) If C itself contains a field where both the simple name and the field descriptor match the target, the direct reference to the field is returned, and the lookup ends.
2) Otherwise, if the interface is implemented in C, the interface and its parent interface will be searched recursively from top to bottom by inheritance, and if found, returns the direct reference to the field and ends the lookup.
3) Otherwise, if C is not an object, the parent class is searched recursively from top to bottom, and if included in the parent class, the lookup ends.
4) Otherwise the lookup fails. Throws a Nosuchfielderror exception.
If a field with the same name appears in both the interface of C and the parent class, or appears in multiple interfaces of itself or the parent class, then the compilation will be rejected.
class method parsing
First parse out the class that belongs to, if parse succeeds, use C to represent this class, the virtual opportunity carries out the following steps:
1) The class method and interface method symbol reference the constant type definition is separate, if the class method table found in the Class_index index of C is an interface, throw the exception directly.
2) in Class C, find out if there is a simple name and description of the Fu Du fish target matching method, if any, return the direct reference to this method, end.
3) Otherwise, look in the parent class of Class C.
4) in the list of interfaces implemented by Class C and their parent interfaces, find out whether a simple name and descriptor match the target, and if so, the class is an abstract class that throws an exception.
5) Otherwise, throw nosuchmethoderror.
Finally, the permission is verified and an illegal access exception is thrown if the permission is not available.
Interface Method Parsing
Parse the symbolic reference of the class or interface to which it belongs, using C to represent this interface:
1) If the index C in the Class_index entry is found in the interface method table as a class rather than an interface, run the exception directly.
2) No Find method in C.
3) Otherwise recursively find in the parent interface of C until the object class.
4) Otherwise the declaration fails.
Because all methods in the interface are public by default, there is no access problem.
Initialize
Is the last stage of the class load, the previous class-loading phase of the user application can be taken over by a custom classloader, and the rest of the actions are entirely dominated and controlled by the virtual machine. In the initialization phase, the Java program code (or bytecode) that is defined in the class is actually executed
The program initialization phase is the process of executing a class constructor method.
- The class constructor method is generated by the compiler to automatically collect the assignment action of the class variable in the class and the statement merge in the static statement block. The order in which the compiler collects is certain to implement variable assignments in static statement blocks, so that static statement blocks can access the initial values of class variables.
- The class constructor method differs from the constructor of the class, it does not need to display the call to the parent class constructor, and the virtual opportunity guarantees that the class construction method of the parent class is completed before the subclass's class construction method executes. So the first class constructed method in a virtual machine is object.
- Because the class constructor method of the parent class executes first, it means that the static statement block defined in the parent class takes precedence over the child class's variable assignment operation.
- Class constructor methods are not necessary for fish or interfaces, and if there are no static statement blocks in a class and no assignment of variables, the compiler can not generate class constructor methods for this class.
- A static statement block cannot be used in an interface, but there are assignment operations for variable initialization, so the interface generates a class construction method like a class. Unlike classes, however, the class construction method of the execution interface does not require the class construction method of the parent class interface, and the implementation class of the interface does not execute the interface's class construction method at initialization time.
- The virtual opportunity guarantees that the class construction method of a class is correctly locking and synchronized in a multithreaded environment.
3.
class Loader
- class-To-Class loaders
Comparing two classes for equality is only meaningful if the two classes are loaded by the same classloader, otherwise, even if the two classes are from the same class file, the two classes must be unequal if they are loaded with different classloader. The so-called "equality" means: the Equals () method, the IsAssignableFrom () method, the Isinstance () method, which represents the class object, also includes the use of the INSTANCEOF keyword as an object-owning relationship judgment.
/** * class loader and instanceof keyword demo * * @author ZZM */ Public class classloadertest { Public Static void Main(string[] args)throwsException {ClassLoader Myloader =NewClassLoader () {@Override PublicClass<?>LoadClass(String name)throwsclassnotfoundexception {Try{String fileName = name.substring (Name.lastindexof (".") +1) +". Class"; InputStream is = GetClass (). getResourceAsStream (FileName);if(IS = =NULL) {return Super. LoadClass (name); }byte[] B =New byte[Is.available ()]; Is.read (b);returnDefineClass (name, B,0, b.length); }Catch(IOException e) {Throw NewClassNotFoundException (name); } } }; Object obj = Myloader.loadclass ("Org.fenixsoft.classloading.ClassLoaderTest"). newinstance (); System.out.println (Obj.getclass ()); System.out.println (objinstanceofOrg.fenixsoft.classloading.ClassLoaderTest); }} Run result: Class Org.fenixsoft.classloading.ClassLoaderTestfalse
As the result shows, when checking the owning type, false is returned because there are two classloadertest classes in the virtual machine, one is loaded by the system application ClassLoader, and the other is loaded by our custom class loader, although all come in the same class file, But it's still two separate classes.
Parental delegation Model
From the point of view of a Java virtual machine, there are only two different classloader: one is to launch the ClassLoader, which is a part of the virtual machine itself, which is implemented by the C + + language, and the other class loaders, all of which are implemented by the Java language, independent of the virtual machine. And all inherit from the abstract class ClassLoader.
From the Java Developer's point of view, the ClassLoader can be more nuanced, and most Java programs use the class loader provided by three systems:
- Launch class loader (Bootstrap ClassLoader): Responsible for storing in <\java_home>\lib\ext directory, or in the path specified by the-xbootclasspath parameter, and is recognized by the virtual machine ( The class library is loaded into virtual machine memory, such as Rt.jar, whose name does not fit in the directory, even if it is not loaded under directories. The startup ClassLoader cannot be referenced directly by a Java program.
- Extension class loader (Extension ClassLoader): This loader is implemented by Sun.misc.launcher$extclassloader, which is responsible for loading the <\java_home>\lib\ext directory, or by java.ext.dirs all class libraries in the path specified by the copper variable, developers can use the extension class loader directly.
- Application class loader (Application ClassLoader): This ClassLoader is implemented by Sun.misc.launcher$appclassloader. Since this classloader is the return value of the Getsystemclassloader () method in ClassLoader, it is generally referred to as the system ClassLoader. He is responsible for loading the class library specified on the user path (ClassPath), which is typically the default ClassLoader in the program if the application does not have its own class loader customized.
Relationship between class Loaders:
The parents delegation model is used in Java to implement the load pattern of a class. The parental delegation model requires that, in addition to the top-level startup ClassLoader, the rest of the ClassLoader should have their own parent ClassLoader, where the parent-child relationship is not implemented with inheritance, but instead uses a combination to take advantage of the parents loader .
Parent delegation Model work process: If a class loader receives a request for a class load, it first does not attempt to load the class itself, but instead delegates the request to the parent class loader, which is the case for each level of the ClassLoader, so all load requests should eventually be routed to the top-level startup class loader. The child loader does not load itself until the parent loader feedback that it is unable to complete the load request (its search scope does not find the desired class).
Implementation of the parental delegation model:
protectedClass<?>LoadClass(String name,BooleanResolvethrowsclassnotfoundexception {synchronized(Getclassloadinglock (name)) {///First, check if the requested class has been loadedclass<?> C = findloadedclass (name);if(c = =NULL) {LongT0 = System.nanotime ();Try{if(Parent! =NULL) {c = parent.loadclass (name,false); }Else{c = findbootstrapclassornull (name); } }Catch(ClassNotFoundException e) {//If the parent class loader throws ClassNotFoundException //indicates that the parent ClassLoader could not complete the load request}if(c = =NULL) {//Parent loader cannot load object //In the Findclass method of calling itself to load the class LongT1 = System.nanotime (); c = findclass (name); } }if(resolve) {Resolveclass (c); }returnC }}
Seventh chapter virtual machine class loading mechanism