Java Virtual machine class loading mechanism

Source: Internet
Author: User
Tags array definition

Original address: http://blog.csdn.net/u013256816/article/details/50829596

See this topic, a lot of people will think I write my Java code, as for the class, the JVM love how to load the loading, bloggers for a long time also think so. With the accumulation of programming experience, more and more feel the importance of understanding the essentials of virtual machine. Gossip not to say, the usual, first a piece of code hanging appetite.

 Public classssclass{Static{System.out.println ("Ssclass"); }}     Public classSuperclassextendsssclass{Static{System.out.println ("Superclass init!"); }     Public Static intValue = 123;  PublicSuperclass () {System.out.println ("Init Superclass"); }} Public classSubclassextendssuperclass{Static{System.out.println ("Subclass Init"); }    Static intA;  PublicSubclass () {System.out.println ("Init Subclass"); }} Public classnotinitialization{ Public Static voidMain (string[] args) {System.out.println (subclass.value); }}
运行结果
ssclasssuperclass Init!123

The answer is correct, hmm?
One might wonder: why not output subclass init. Ok~ explains that for a static field, only the class that directly defines the field is initialized, so referencing the static field defined in the parent class through its subclasses will only trigger the initialization of the parent class without triggering the initialization of the subclass.
The above involves the virtual machine class loading mechanism. If you are interested, you can continue to watch.

Class loading process

Class starts from being loaded into the virtual machine's memory, and its entire lifecycle includes: Load (Loading), validate (verification), prepare (preparation), Parse (Resolution), Initialize ( initialization), use (using), and unload (unloading) 7 stages. Where preparation, validation, parsing 3 parts collectively referred to as the connection (linking):

The order of the 5 stages of loading, validating, preparing, initializing, and unloading is determined, and the load process of the class must begin in this order, and the parsing phase is not necessarily: it can be started after the initialization phase in some cases, This is to support runtime bindings for the Java language (also known as dynamic binding or late binding). The following statements are in the context of hotspot.

Loading

During the load phase (you can refer to Java.lang.ClassLoader's LoadClass () method), the virtual machine needs to complete the following 3 things:

    1. A binary byte stream that defines this class is obtained through the fully qualified name of a class (it is not specified to be obtained from a class file, from other channels, such as: network, dynamic generation, database, etc.);
    2. Transform 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 memory as the access entry for various data of this class in the method area;

Portions of the load phase and connection phase (linking), such as some bytecode file format validation actions, are interleaved, the loading phase is not complete, the connection phase may have begun, but the actions taken during the loading phase of these clips are still part of the connection phase, The start time of the two phases remains in a fixed sequence.

Validation

Validation is the first step in the connection phase, which is designed to ensure that the information contained in the byte stream of a class file conforms to the requirements of the current virtual machine and does not compromise the security of the virtual machine itself .
The validation phase will roughly complete the 4-phase inspection action:

    1. File Format verification: Verify that the byte stream conforms to the specification of the class file format, for example: whether to start with magic 0xCAFEBABE, whether the primary and secondary version number is within the processing range of the current virtual machine, and whether the constants in the constant pool have unsupported types.
    2. Meta-data validation: Semantic analysis of the information described in bytecode (note: Comparing the semantic analysis of the JAVAC compilation phase) to ensure that the information it describes conforms to the requirements of the Java language specification, for example: Whether this class has a parent class, except Java.lang.Object.
    3. Bytecode verification: Through data flow and control flow analysis, it is reasonable to determine that the program semantics are legal and logical.
    4. Symbol Reference Validation: Ensures that parsing actions are performed correctly.
    5. Validation of two-tier compatibility: Ensure consistency between classes that are referenced to each other. For example, the run () method of the car class is called in the Gotowork () method of the worker class, and when the Java Virtual machine validates the worker class, it checks to see if there is a run () method for the car class in the method area. If it does not exist
      Throws a nosuchmethoderror error on the back

The validation phase is important, but not necessary, and it has no effect on the program runtime, and if the referenced classes are repeatedly validated, consider using the-xverifynone parameter to turn off most of the class validation measures to shorten the load time of the virtual machine class.

Prepare

The prep phase is a phase that formally allocates memory for class variables and sets the initial value of class variables, and the memory used by these variables is allocated in the method area. The memory allocation at this time includes only class variables (variables that are modified by static), not instance variables, and instance variables are allocated to the heap as objects are instantiated. Second, the initial value referred to here is the 0 value of the data type, assuming that a class variable is defined as:

    public static int value=123;

The initial value of the variable value after the prep phase is 0 instead of 123. Since no Java methods have been executed at this time, the putstatic instruction that assigns value 123 is that the program is compiled and stored in the class constructor () method. So an action that assigns value to 123 will not be executed until the initialization stage.
As for "special case" means: public static final int value=123, that is, when the field property of a class field is Constantvalue, it is initialized to the specified value in the preparation phase, so after the label is final, Value is initialized to 123 instead of 0 in the prepare phase.

parsing

The parsing phase is the process by which a virtual machine replaces a symbolic reference within a constant pool with a direct reference. Parsing actions are primarily for classes or interfaces, fields, class methods, interface methods, method types, method handles, and call Point qualifier 7 class symbol references.

For example, the run () method of the car class is referenced in the Gotoworker () method of the Worker class

In the worker class's binary data, a symbolic reference to the run () method of the car class is included, which consists of the full name of the run () method and the associated description.

During the parsing phase, theJava virtual Opportunity replaces this symbolic reference with a pointer to the run () method of the car class in the memory location where the method goes, and the pointer is a direct reference.

 Public void gotowork () {            car.run (); // This code is represented as a symbol reference in the worker class's binary data   }

Initialize

The class initialization phase is the last step in the class loading process, and in the initialization phase, the Java program code defined in the class is really started . In the preparation phase, the variable has already assigned the initial value of the system requirement, and during the initialization phase, the class variables and other resources are initialized according to the program's subjective plan, or the initialization phase is the process of executing the class constructor <clinit> () method.
The <clinit> () method is generated by the compiler's automatic collection of assignment actions for all class variables in the class and statements in the static statement block static{}, and the order in which the compilers are collected is determined by the order in which the statements appear in the source file. A static statement block can only access variables that are defined before a static statement block, a variable that is defined after it, and a block of static statements in front of it may be assigned, but cannot be accessed. As follows:

public class Test{    static    {        i=0;        System.out.println(i);//这句编译器会报错:Cannot reference a field before it is defined(非法向前应用) } static int i=1;}

Then the sentence to remove the error, change to the following:

public class Test{    static    {        i=0;// System.out.println(i); } static int i=1; public static void main(String args[]) { System.out.println(i); }}

What is the result of the output? Of course it's 1. In the preparation phase we know i=0, then the class initialization phase executes sequentially, first executes the i=0 in the static block, then executes the static assignment operation I=1, and finally gets the value of I in the main method of 1.

The <clinit> () method differs from the instance constructor <init> () method in that it does not require a display to call the parent class constructor, and the virtual opportunity guarantees that the parent class's <clinit> before the subclass <cinit> () method executes () method has been executed , return to the example code at the beginning of this article, the result will be printed output: Ssclass is the truth.
Because the <clinit> () method of the parent class executes first, it means that the static statement block defined in the parent class takes precedence over the variable assignment operation of the child class.
The <clinit> () method is not required for a class or interface, and if there is no static statement block in a class, and there is no assignment to the variable, the compiler can not produce the <clinit> () method for this class.
A static statement block cannot be used in an interface, but there are still assignment operations for variable initialization, so the interface will generate the <clinit> () method as the class. However, unlike the class interface, the <clinit> () method of the execution interface does not require the parent interface's <clinit> () method to be executed first. The parent interface is initialized only if the variables defined in the parent interface are used. In addition, the implementation class of the interface does not execute the <clinit> () method of the interface at initialization time.
The virtual opportunity guarantees that a class <clinit> () method is correctly locking 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. Other threads need to block the wait until the active thread executes the <clinit> () method. If there is a lengthy operation in the <clinit> () method of a class, it can cause multiple threads to block, which is often hidden in real-world applications.

Package jvm.classload;PublicClass deallooptest{Static Class Deadloopclass {static {Iftrue) {System.Out.println (Thread.CurrentThread () +"Init Deadloopclass");While (true) {}}}} public static void main (string[] args) {Runnable script = new Runnable () { public void Run () {System. out.println (Thread.CurrentThread () +"Start"); Deadloopclass DLC = new Deadloopclass (); System. out.println (Thread.CurrentThread () +"run Over");}; Thread thread1 = new Thread (script); Thread thread2 = new Thread (script); Thread1.start (); Thread2.start ()       ;}} 

Run Result: (i.e. one thread in a dead loop to simulate a long operation, another thread blocking waiting)

Thread[Thread-0,5,main] startThread[Thread-1,5,main] startThread[Thread-0,5,main]init DeadLoopClass

It is important to note that while other threads are blocked, if the thread that executes the <clinit> () method exits the <clinit> () method, the other thread wakes up without re-entering the <clinit> () method. under the same ClassLoader, a type is initialized only once.

Replace the static block in the above code with the following:

        static        {            System.out.println(Thread.currentThread() + "init DeadLoopClass"); try { TimeUnit.SECONDS.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } }

Operation Result:

Thread [thread-0,5,main] Startthread[thread-1, 5,main] startthread[Thread-< Span class= "Hljs-number" >1,5,main]init deadloopclass (after sleep  10s) thread[thread-1,5,main] Run Overthread[Thread-0,5,main" Run over        

The virtual machine specification strictly stipulates that only 5 of the cases (jdk1.7) must "initialize" the class (while loading, validating, and preparing the natural need to start before this):

    1. When encountering new,getstatic,putstatic,invokestatic this offset bytecode directive, if the class has not been initialized, it needs to trigger its initialization first. The most common Java code scenario for generating these 4 instructions is when instantiating an object using the New keyword, reading or setting a static field of a class (except for the static field that was final decorated, which has been placed in a constant pool by the compiler), and when invoking a static method of a class.
    2. When you use the Java.lang.reflect package method to make a reflection call to a class, if the class has not been initialized, you need to trigger its initialization first.
    3. When initializing a class, it is necessary to trigger the initialization of its parent class if it finds that its parent class has not yet been initialized.
    4. When the virtual machine starts, the user needs to specify a main class to execute (the class that contains the main () method), and the virtual opportunity initializes the main class first.
    5. When using jdk1.7 Dynamic language support, if a java.lang.invoke.MethodHandle instance finally resolves the result ref_getstatic,ref_putstatic,ref_invokestatic the method handle, And the class that corresponds to this method handle is not initialized, it needs to be initialized before it is triggered.

The beginning has already cited an example: a static field that has been paid by reference to a subclass does not cause the subclass to initialize.
Here are two more examples.
1. referencing a class through an array definition does not trigger initialization of this class : (The superclass class is defined at the beginning of this article)

public class NotInitialization{    public static void main(String[] args) { SuperClass[] sca = new SuperClass[10]; }}

Operation Result: (none)
2. 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:

public class ConstClass{    static    {        System.out.println("ConstClass init!"); } public static final String HELLOWORLD = "hello world";}public class NotInitialization{ public static void main(String[] args) { System.out.println(ConstClass.HELLOWORLD); }}

Run Result: Hello World

Attached: Yesterday from the forum to see an example, very interesting, as follows:

Package jvm.classload;PublicClass statictest{PublicStaticvoidMain (string[] args) {staticfunction ();}static Statictest St =New Statictest ();static {system. Out.println ( "1");} {System. out.println ( "2");} Statictest () {system. Out.println ( "3"); System. out.println ( "a=" +a+public static void staticfunction () {system. Out.println ( "4");} int a=110; static int b =112;} 

/span>
The question is: What is the output?

Program run to know the results, if you want to know why, please leave a message ~ ~

Plus: The explanation of the problem has been sorted out, welcome to the Java Virtual machine class loading mechanism-case study

References: "In-depth understanding of Java Virtual machines" Zhou Zhiming.

Java Virtual machine class loading mechanism

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.