In-depth understanding of Java Virtual Machines (4)---class loading mechanism

Source: Internet
Author: User
Tags throw exception

The process of class loading includes:

Load class to memory, data check, transform and parse, initialize, use using and unload unloading process.

In addition to the parsing phase, the order of the other processes is fixed. Parsing can be placed after initialization to support dynamic loading.

From the Java developers, we don't care about the specifics, just know the whole process and each process is doing roughly that.

Each process can have a specific impact on the development code.

One: Load flow of Class 1. Load loading

During the loading process, the virtual machine needs to complete 3 things:

1) This type of binary byte stream is obtained by the fully qualified name of a class.

2) transform the static storage structure of this direct stream into the runtime data structure of the method area.

3) Generate a class object in memory that represents the category as a data access entry for the class of the method area.

2. Verification

Validation is a very important step for a virtual machine to ensure that the byte stream of the class file conforms to the requirements of the Java Virtual machine itself and does not cause the virtual machine to crash.

The Java language itself is a more secure language, and it does not occur when arrays are out of bounds. But,class languages are not necessarily generated by the Java language. Even

You can write class files directly using the 16 binary tool. These documents do not guarantee the normative class file.

The verification process is roughly divided into 4 phases: file Format Verificationmeta-data validationbyte code verificationAnd Symbol Reference ValidationFile format verification: such as whether to start with the magic number, major and minor version number is within the scope of the virtual machine can be processed, the constant pool is not supported type, and so on. after this phase of validation, the byte stream will be stored in the memory's method areaSo The following three verification phases are all based on the storage structure of the method area。 Metadata validation: The information that is described by the byte code is Semantic AnalysisTo ensure that the information it describes conforms to the requirements of the Java language Specification, which may include a validation point that includes whether the class has a parent class, whether the parent class integrates a class that does not allow inheritance, or whether the field in the class and the parent class are inconsistent if the class is not implementing all of the methods required in its parent class or interface Bytecode verification: one of the most complex interpretations that, the main work is perform data flow and control flow analysis。 At this stage, the method body of the class is verified and analyzed to ensure that the method does not make the behavior that harms the JVM security at runtime, for example: to ensure that the data type and instruction code sequence of the operand stack at any time can work together to ensure that the jump instruction does not jump to the bytecode instruction outside the method body. Ensure that the type conversion in the method body is valid ... This verification does not guarantee a certain safety ( stop problem, through the program to verify the program logic is not absolutely accurate1.6 Adding the Stackmaptable function optimizes this phase and improves speed, but this stackmaptable can also be tampered with, and it is possible to turn this option off with the start parameter. Symbol Reference Validation: This stage occurs when a virtual machine converts a symbolic reference to a direct reference. This conversion action will occur during the third phase of the connection----the parsing phase。 Can be seen as a validation of the matching of information other than the class itself. For example: the fully qualified name of the symbol reference in the string description can find the corresponding class, whether there is the method and the field described .... If the symbol cannot be verified, a subclass of the Java.lang.IncompatibleClassChangeError exception will be thrown, such as Java.lang.IllegalAccessError, Java.lang.nosuchfielderror,java.lang.nosuchmethoderror You can use the startup parameters to turn off most of the class validation measures to shorten the load time of the virtual machine class。 3. Preparation

The preparation stage is to formally allocate memory for the variables of the class and set the initial values. This initial value is not the same concept as initialization.

Like what

 Public Static int value = 12;

At this stage value is 0 instead of 12. Value is assigned a stage of 12

Occurs during the initialization process. All basic types in Java are assigned a value of zero. (simply say 0 or null,0.0f,false, etc.) 4. Parsing

Parsing is the object-oriented foundation of the Java language.

Parsing is the process of replacing a character reference inside a constant pool with a direct reference .

A symbol reference is a set of symbols that describe the target being referenced. The memory layouts for various virtual machines can vary, but the literal form is strictly defined by the virtual machine specification.

A direct reference is a direct description of the virtual machine's memory layout.

So the target of the reference must already be loaded into memory.

1). Parsing of classes or interfaces

Class and interface parsing: Assuming that the current code is in the Class D, if you want to parse an never-parsed symbol reference n into a direct reference to a class or interface C, the virtual machine needs the following three steps to complete the parsing process:

If C is not an array type, the virtual machine will pass the fully qualified name representing N to the class loader of D to load the class C.

If C is an array type, and the element type of the array is an object, it is handled as 1. if the element type is not an object, the virtual machine generates an Array object that represents this array dimension and element .

If there is no exception to the above steps, C has become a valid class or interface in the virtual machine century, but before parsing is complete, symbolic reference validation is performed, confirming that C has access to D, and if not, throws a Java.lang.IllegalAccessError exception.

2). Field resolution

The overall situation is as follows:

class d{      public  D (c c)    {         = c.a;       }  }    

D needs to load the C.A field, first of all, to load the parsing content of Class C. Then the key part is the Java language inheritance.

If the Class C contains a field, the direct reference to a is returned directly.

Search the interface of Class C, follow the inheritance relationship from top to bottom to search for the parent interface of each interface until the A field is found. If not

If C is not the Java.lang.Object, ditto, search for the parent class of class C, if any, use the direct reference to the field. If not

That is, the C class and its related classes or interfaces do not have this field, and the lookup fails.

If found, permission validation is also required.

If the interface & class contains fields of the same name, Java programmers sometimes cannot tell which field to use.

So the compiler generally rejects this situation.

The following are the results of using the Androidstudio experiment:

 Public InterfaceICoo { Public Static intA = 1;} Public Abstract classcooabstruct { Public intA = 22;} Public classCooextendsCooabstructImplementsICoo {//public int Geta ()//    {//return A;//    }}
 Public class Doo {    public  Doo (Coo c)    {        int a  = c.a;    }}

E:\github\jvmdemo\app\src\main\java\com\joyfulmath\myapplication\doo.java:13: Error: Ambiguous reference to a, variable in cooabstruct The variable A in a and Icoo match
int a = C.A;
^
1 errors

As you can see, the compiler is clearly unable to tell which field a is using.

In multiple inheritance of C + +, a similar situation needs to be used to clarify exactly which subclass of the field is used.

3) method loading of the class:

Also use Class C to describe this process:

Class methods and interface methods are separated by constant types. So if the C-class method finds a method of an interface, the exception is thrown directly back. Type detection.

Search directly in class C for a method that matches the character description. No, just go on.

In the parent class of Class C, search recursively, without continuing

In the Class C interface recursive search, find, show that this method is not implemented, Class C is an abstract class. Throw exception

Have not found, Nosuchmethod.

If a valid matching method is found, check the permissions.

4) How to load the interface

The process of the same method is basically the same. Just do not need a permission check.

Two. Initialization

The initialization and preparation phases are different processes and are the most relational part of the Java programmer.

1. Conditions that must be initialized

The Java Virtual Machine specification specifies 5 (and only) operations that must be initialized.

1) When encountering the New,getstatic,putstatic,invokestatic 4 instructions. Corresponding scenario:

Instantiate a class, read or set a static field of a class, and call a static method of a class.

2) When using the Reflection method call, you need to initialize it first.

3) When you start a class, you need to initialize the parent class first.

4) When the virtual machine starts, you need to specify a startup class (main Class), and the virtual opportunity initializes the class first.

5) When using jdk1.7 Dynamic language, this article does not do analysis.

Use a few demos to illustrate where we can easily misunderstand:

 public  class  mainactivity extends   Activity {@Override  protected< /span> void   OnCreate (Bundle savedinstancestate { super  .oncreate (Savedinstancestate)        ;        Setcontentview (R.layout.activity_main);    TRACELOG.I (string.valueof (Subclass.value)); }}
 Public class extends Superclass {    static  {        tracelog.i ("Subclass init!" );    }}  Public class Superclass {    static  {        tracelog.i ("Superclass init!" );    }      Public Static int value =n;}

Result log:

05-08 10:10:33.783 868-868/com.joyfulmath.myapplication i/superclass: <clinit>: SuperClass init! [At (SUPERCLASS.JAVA:13)]
05-08 10:10:33.783 868-868/com.joyfulmath.myapplication i/mainactivity:oncreate:12 [at (MainActivity.java:19)]

Yes, only the parent class is initialized, the subclass is not initialized, why?

The parent class should be defined for value, so it is only necessary to initialize the parent class.

 Public class Superclass {    static  {        tracelog.i ("Superclass init!" );    }      Public Static int value =n;      Public Superclass ()    {        tracelog.i ("superclass construct");}    }

Instantiation of the construction function did not go, so no instances were created!!! But, we are looking at log,<clinit> this is God horse? This is the function of printing Superclass.init!!!

This wait until the following is said, we continue our demo.

    @Override    protectedvoid  onCreate (Bundle savedinstancestate) {         Super . OnCreate (savedinstancestate);        Setcontentview (r.layout.activity_main); //         tracelog.i (string.valueof (Subclass.value));         tracelog.i ();        Superclass[] A  new superclass[10];    }

05-08 10:22:33.100 12438-12438/com.joyfulmath.myapplication i/mainactivity:oncreate: [at (MainActivity.java:21)]

What? There is no row log for superclass, that is, there is no initialization of superclass at all.

It triggered a class for "[XXX]. Superclass ", this is the superclass corresponding array class, which is generated automatically by the virtual machine.

TRACELOG.I (A[0].tostring ());
 caused By:java.lang.NullPointerException:Attempt to invoke virtual method ' java.lang.String Java.lang.Object.toString () ' On a 

A[0] is it actually null? Yes, the array A is null. The pair of a is just an array, the type of A is "[XXX]. Superclass "is not superclass. Therefore, the array does not initialize the metadata automatically.

Constant.

Constants are stored inside a constant pool, so references to constants are optimized during the compilation phase.

Let's talk about <clinit> this stuff.

Static code block + assignment action for variables of all classes.

Here's one thing to emphasize: the order in which the compilers are collected is consistent with the order in which the source code is in the file.

The <clinit> () method is a combination of the copy action of all class variables in the compiler's auto-collection class and the statements in the static statement block. The order in which the compiler collects is consistent with the order in which the statements appear in the source file, the static statement block can only access variables defined before it, variables defined after it, can only be assigned values, cannot access

The <clinit> () method differs from the class's constructor <init> () and does not require an explicit call to the parent class constructor, which guarantees that the parent class's <clinit> () is completed before the child class. Therefore, the first <clinit> () method performed by a virtual machine is definitely java.lang.Object.

Because the parent class <clinit> () method executes first, it means that the static statement defined in the parent class takes precedence over the variable assignment operation of the child class.

The <clinit> () method is not required, and if a class does not have a static statement block and does not assign a value to a variable, it does not generate

The static statement block cannot be used in an interface, but there are still variables that initialize the assignment, so the <clinit> () method is also generated, but unlike the class, the <clinit> () method of the interface does not need to perform the <clinit> () method of the parent interface. The parent interface is initialized only when a variable defined in the parent's mouth is used, and the implementation class of the interface does not execute the <clinit> () method of the interface as it was initialized.

Virtual opportunity to ensure that a class of <clinit> () method in the multi-threaded environment in the correct lock synchronization, if multiple threads to initialize a class at the same time, then there will only one thread to execute the class of the <clinit> () method, the other threads will block, Until the method executes, if there is a long-time operation in the <clinit> () method of a class, it can cause multiple processes to block, and in practice, the blocking is often subtle.

Reference:

"In-depth understanding of Java Virtual machines" Zhou Zhiming

In-depth understanding of Java Virtual Machines (4)---class loading mechanism

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.