The virtual machine loads the description class data from the class file into the memory, verifies the data, transforms and initializes it, and eventually forms a Java type that can be used directly by the virtual machine, which is the class loading mechanism of the virtual machine.
The lifecycle of a class is loaded (Loading), validated (verification), prepared (preparation), parsed (resolution), and so on, starting from the class loading into the virtual machine memory, until the memory is unloaded. Initialization (initialization), use (using), and uninstall (unloading) 7 phases
Where validation, preparation, and parsing are called connections, in the Java language, the load and join process of a type is done during the program run (Java can dynamically expand the language feature that relies on runtime dynamic loading, dynamic connection, and so on), which adds a bit of performance overhead to the class load. But it provides a high degree of flexibility for Java applications
Load, verify, prepare, initialize, and uninstall the order of the 5 phases is fixed (that is, the load phase must begin before the validation phase begins, and the verification phase must start before the preparation phase begins.) These phases are all interleaved, usually in one phase of the execution of the call or activation of another phase, the parsing phase is not necessarily, in some cases, the parsing phase may be at the end of the initialization phase, to support Java dynamic binding
load (Loading)
Start time:
The load phase is a phase of the class loading process, and the virtual machine specification does not enforce constraints on when to start the first phase of the class loading process: load, but to the virtual machine to achieve the specific realization of the free grasp, However, the virtual machine specification strictly stipulates that there are only 4 cases (these 4 cases will be introduced in the later initialization section), the class must be initialized immediately, and the corresponding loading, verification and preparation phases will naturally begin before the initialization phase begins
Task:
In the load phase, the virtual machine needs to complete the following three things (the virtual machine specification is not specific to these three things, so the virtual machine implementation and specific application flexibility is quite large):
1, obtains the binary stream that defines this class through the fully qualified name of a class
Can be obtained from jar packs, ear packs, war packs, can be obtained from the network (applets), can be run-time generation (dynamic proxy), can be generated by other files (JSP), etc.
The virtual machine specification does not indicate that the binary stream is to be retrieved from a class file. To be exact, there is no indication of where to get and how to get it (you can complete the loading phase by reading the twos stream through the class loader of your own implementation, but generally the source of the binary stream is the class file, A class file is saved in the jar, and the JSP is first compiled into a class file.
2, converts the static storage structure represented by this byte stream into the RUN-TIME data structure of the method area
The virtual machine specification does not specify the data structure of the method area to store the information, and the data storage format is defined by the virtual machine.
3, a Java.lang.Class object representing this class is generated in the Java heap as the access gate to the data in the method area
validation (verification)
Start time:
The load phase is interleaved with part of the connection phase, such as part of the bytecode file format verification action. The load phase has not yet ended, the connection phase may have begun, this part of the inclusion in the loading phase of the action, is still part of the connection phase of the content, and the loading phase must be earlier than the connection phase start
Task:
The first step in the connection phase ensures that the information contained in the byte stream of the class file meets the requirements of the current virtual machine and does not compromise the security of the virtual machine itself
The Java language itself is a relatively secure language (as opposed to C + +), using pure Java code does not make it possible to access data outside the array bounds, transform an object into its data type that it does not implement, jump to a nonexistent line of code, and if so, the compiler will reject the compilation, But the class file is not necessarily compiled from the Java source, can be used in any way, such as: using a hexadecimal editor directly to produce class files, at the bytecode level, the above Java code can not do things are achievable, at this time, if the virtual machine does not check the input of the byte stream, It is possible that the system crashes due to the loading of harmful byte streams, so an important task for the virtual machine to protect itself when validating
The virtual machine specification is very general about this stage, and only requires that if you verify that the byte stream that you entered does not conform to the storage format of the class file, you throw a Java.lang.VerifyError exception (the JDK1.6 API document describes the exception class as: "When the validator" A class file was detected with the correct format however, when there are some internal inconsistencies or security issues, the error is thrown, or its subclass exception, the specific check which aspects, how to check, when the check, did not make mandatory or clear, so the different virtual machines to verify the implementation of different, However, the following 4 phases of the inspection process are generally completed:
1, File Format verification
Verify that the byte stream conforms to the class file format specification and whether it can be processed by the current version of the virtual machine (such as whether to start with the magic number 0xCAFEBABE, the primary and secondary version number within the current Virtual machine processing range, etc.)
The primary purpose of this phase is to ensure that the input byte stream is parsed correctly and stored in the method area, in a format that conforms to the requirements for describing a Java type information
This phase of verification is based on the byte stream, after this phase of validation, the byte stream will enter the memory of the method area for storage, so the following three verification phase is based on the method area of the storage structure
2, Meta data validation
A semantic analysis of the information described by the bytecode (that is, the class's metadata information) to ensure that the information it describes conforms to the requirements of the Java language Specification (such as whether the class has a parent class, inherits classes that are not allowed to be inherited, etc.)
3, byte code verification
Data flow and control flow analysis, that is, the class of the method of validation analysis to ensure that the method of validation of the class is not to do harm to the virtual machine security behavior (such as: to ensure that the jump instructions do not jump to the method body of the byte Code instructions, etc.)
Even if a method passes the bytecode verification, it does not mean that it must be safe (through the program to verify the program logic can not be absolutely accurate)
The Javac compiler after JDK1.6 has an optimization that adds a new attribute to the property sheet of the Code property of the method body: stackmaptable, which holds the type information in the method body, can make the type deduction at the time of byte code validation into type checking to save time. The-xx:-usesplitverifier option is available in the JDK1.6 hotspot virtual machine to turn off this optimization, or use the-xx:+failovertooldverifier option to revert to using type inference for validation when type checking fails
4, Symbolic reference verification
Match the information outside of the class itself (for example, whether the fully qualified name described in the symbolic reference can find the corresponding class, the specified class has a method and a field that conforms to the descriptor and the simple name description)
The checksum occurs when a virtual machine converts a symbolic reference to a direct reference, which occurs during the third phase of the connection: parsing phase to ensure that the parsing action is performed correctly, if it cannot be validated by symbolic references, Will throw a Java.lang.IncompatibleClassChangeError exception (especially if it inherits from Java.lang.Error instead of java.lang.Exception), and its subclasses are usually errors caught by the compiler
If all of the code running has been reused and validated, you can use the-xverify:none parameter to close most of the class validation measures in the implementation phase to shorten the time that the virtual machine class is loaded
Preparation (preparation)
Task:
In the preparation phase, the virtual machine allocates memory for the class variable (the static-decorated variable) and sets the class variable initial value. These memory will be allocated in the method area
There are 2 areas where special emphasis is needed:
1, the memory allocation at this stage includes only class variables, excluding instance variables, which are allocated in heap memory along with the object when the object is initialized
2, here the initial value "usually" refers to the data type of the 0 value, such as a class variable defined as: public static int a = 1, and variable A after the preparation phase of the value of 0 instead of 1
The program compiles a putstatic instruction that assigns a value of 1 and stores the instruction in the class constructor <clinit> (), so the action of a assignment of 1 is completed in the initialization phase
If the field property sheet of the Class field contains the Constantvalue property, the preparation stage variable is initialized to the value specified by the Constantvalue property, that is, if a variable definition becomes public final static int a = 1; Compile-time Javac generates a Constantvalue attribute for a, and the prep-phase virtual machine sets a value to 1 based on constantvalue settings
The basic data type 0 values are as follows:
Data type |
0 value |
Byte |
(byte) 0 |
Char |
' \u0000 ' |
Short |
(short) 0 |
Int |
0 |
Long |
0L |
Float |
0.0f |
Double |
0.0d |
Boolean |
False |
Reference |
Null |
Parsing (resolution)
Start time:
The virtual machine specification does not specify the time when the parsing action takes place and requires only the execution of Anewarray, Checkcast, GetField, Getstatic, instanceof, Invokeinterface, Invokespecial, Invokestatic, Invokevirtual, Multianewarray, New, Putfield, and putstatic these 13 byte-code directives used to manipulate symbolic references are parsed
Task:
The parsing phase is the process by which a virtual machine replaces a symbolic reference in a constant pool (see note i) with a direct reference (see note II)
It is common to have multiple resolution requests for the same symbolic reference, which may cache the results of the first resolution (the direct reference is stored in the Run-time pool), and the virtual machine implementation must be in the same entity, regardless of whether a multiple resolution action is actually performed. If a symbolic reference has been successfully parsed before, subsequent reference resolution requests should always succeed and vice versa
Parsing action is mainly for class or interface, field, class method, interface method, four kinds of symbolic reference, corresponding to the constant pool of constant_class_info, Constant_fieldref_info, Constan_methodref_info, Constant_interfacemethodref_info Four types of constants
Before parsing a field, class method, or interface method symbol reference, the preference is to parse the symbolic reference of its containing class (see constant pool constant structure, constant_fieldref_info, Constan_methodref_info, Constant_ The index of the descriptor for the class or interface that declares the field, class method, interface method, Interfacemethodref_info, is stored in the type constant: An index of a constant_class_info type constant
initialization (initialization)
Start time:
The class must be initialized immediately with only 4 cases:
1, encounters new (with the new keyword to instantiate the object), Getstatic (Gets the static field of a class, except for the static field that the final modifier modifies), putstatic (sets a static field for a class, Except for static fields that are decorated by the final modifier and invokestatic (a static method that invokes a class), if the class has not yet been initialized, it must first be initialized with the 4 byte code instruction.
2, when a class is reflected by using the method in the Java.lang.reflect package, if the class has not yet been initialized, it must be initialized first
3, when a class is initialized, if its parent class has not yet been initialized, it must first initialize its parent class
4, when the virtual machine is started, you need to specify a main class (the class in which the main method is located), and the virtual opportunity first initializes the main class
These 4 behaviors are called active references to a class, except that all references to classes do not trigger initialization, called passive references
Package com.test;
public class Superclass {
static{
System.out.println ("Super Class init!");
}
public static int a = 1;
Public final static int b = 1;
}
Package com.test;
public class subclass extends superclass{
static{
System.out.println ("Super Class init!");
}
Test One:
-xx:+traceclassloading public
class Test {
static{
System.out.println ("Test class init!");
}
public static void Main (string[] args) {
System.out.println (SUBCLASS.A);
}
The results of the operation are:
......
[Loaded com.test.Test from file:/d:/eclipseproject/1/bin/]
Test class init!
[Loaded Com.test.SuperClass from file:/d:/eclipseproject/1/bin/]
[Loaded Com.test.SubClass from file:/d:/eclipseproject/1/bin/]
Super class init!
1. ...
For static fields, only classes that directly define this field are initialized, so only the parent class is initialized and the subclass is not initialized (the subclass is invoked in a way that does not conform to any of the 4 direct references); The test class is a program entry and is also initialized.
Whether to trigger the loading and validation of subclasses, the virtual machine specification is not clearly defined, depending on the virtual machine implementation, the Hotspot virtual machine, can be seen through the-xx:+traceclassloading parameters of this operation will cause the loading of subclasses
Test Two:
public class Test {public
static void Main (string[] args) {
superclass[] temp = new SUPERCLASS[10];
}
The output is empty
Test Three:
public class Constant {
static{
System.out.println ("Constant class init!");
Public final static int a = 1;
}
public class Test {public
static void Main (string[] args) {
System.out.println (CONSTANT.A);
}
}
Run Result:
1
In the compile phase, the value 1 of constant A will be placed in the constant pool of the test class, and the reference to the constant constant.a is actually translated into a reference to the test class to its own constant pool, which has no relation after compiling the class file.
Task:
The class initialization phase is the last step in the class loading process. In the previous phase, in addition to the load phase user application can participate through the custom ClassLoader, the other stages are completely driven and controlled by the virtual machine, until the initialization phase, to really start executing the Java program code defined in the class
In the preparation phase, the variable has already been assigned an initial value, in the initialization phase, it is based on the programmer through the program of the subjective plan to initialize class variables and other resources, simply, the initialization phase is the virtual machine to execute the class constructor <clinit> () method process, the following detailed description of the following < Clinit> Method:
<clinit> is generated by the compiler automatically collecting the assignment actions of all class variables in the class and the statement merges in the static statement block. The order that the compiler collects is determined by the order in which the statement appears in the source file, with particular attention to the static statement block accessing only the class variables defined before it. The class variable that is defined after it can only be assigned a value and cannot be accessed
public class Test {public
static int a = 1;
static{
a = 1;
System.out.println (a);
b = 2;
Cannot reference a field before it is defined
//b = 1;
System.out.println (b);
}
public static int b = 1;
public static void Main (string[] args) {
test test = new test ();
System.out.println (test.b);
}
The run result is (the collection order is determined by the order in which it is in the original file, so the value of B here is 1 instead of 2):
2
1
Unlike the instance constructor <init> () method, the,<clinit> method does not need to explicitly invoke the <clinit> () method of the parent class, and the virtual opportunity automatically guarantees that the class's <clinit> () method is run before the The <clinit> () method has finished executing, and the first class to execute the <clinit> () method in the virtual machine is Java.lang.Object
public class Superclass {
static{
System.out.println ("Super Class init!");
}
public class subclass extends superclass{
static{
System.out.println ("Sub Class init!");
public static void Main (string[] args) {
Subclass sub = new subclass ();
}
The results of the operation are:
Super class init!
Sub Class init!
The <clinit> () method is not necessary for a class or interface, and if a class does not contain a static statement block or an assignment to a class variable, the compiler may not generate a <clinit> () method for that class
Static statement blocks can not be used in interfaces, but can have assignment operations on class variables, so compilers also generate <clinit> () methods on interfaces, and do not require the implementation of the <clinit> () method of the interface first to execute the <clinit> () of the parent interface. method, the interface implementation class does not necessarily require the <clinit> () method of the interface to be executed first, unless the class variables initialized in the parent interface are used in the interface.
Virtual opportunity guarantees that a class's <clinit> () method is correctly lock and synchronized in a multithreaded environment, and if multiple threads initialize a class at the same time, only one thread executes the <clinit> () method of the class, and other threads block the wait. Until the active thread Execution <clinit> () method is complete
public class A {
static{
System.out.println (Thread.CurrentThread (). GetName ()
+ "" +new Date ());
try {
Thread.Sleep (5000);
} catch (Interruptedexception e) {
e.printstacktrace ();
}
}}
public class T implements Runnable {public
void run () {
A A = new A ();
System.out.println (Thread.CurrentThread (). GetName ()
+ "" +new Date ());
}
public static void Main (string[] args) {
T t1 = new T ();
T t2 = new T ();
Thread thread1 = new Thread (t1);
Thread thread2 = new Thread (t2);
Thread1.start ();
Thread2.start ();
}
Run result (only one thread executes the code in a static statement block in Class A):
Thread-0 Fri Dec 10:25:00 CST 2013
Thread-1 Fri Dec 10:25:05 CST 2013
Thread-0 Fri Dec 10:25:05 CST 201 3
Ps:
1, Symbolic Reference: a set of symbols to describe the referenced target, the symbol can be any form of literal, as long as the use of ambiguity can be positioned to the target. Symbolic references are independent of the memory layout implemented by the virtual machine, and reference targets are not necessarily loaded into memory
2, direct reference: direct pointer to the target, relative offset, or a handle indirectly positioned to the target, directly referencing the memory layout implemented by the virtual machine, if there is a direct reference, the reference target must have been loaded into memory