An incomplete study summary of "deep understanding of Java Virtual Machine" in Reading Notes,

Source: Internet
Author: User

An incomplete study summary of "deep understanding of Java Virtual Machine" in Reading Notes,

Preface:

The reason for this is incomplete summary, because I have not fully read this book, but it covers most important chapters. At the same time, the conclusion below is that I think it is very important, and it is inevitable to omit the details, for more information, see the original document.

Reprinted please indicate the original source: http://www.cnblogs.com/qcblog/p/7704788.html

1. java memory Zone

1.1 runtime data Zone

The program counter is the memory space for thread isolation, and is the only region in the specification that does not specify OutOfMemoryError.

The Virtual Machine stack is also an area of thread isolation. The call of a method is based on the stack frame, and the stack is inbound and outbound in the Virtual Machine stack. Stack frames are mainly used to store information such as local variable tables, Operation stacks, dynamic links, and method exits. StackOverflowError or OutOfMemoryError may occur in this area.

The local method stack mainly serves native methods.

Heap memory is an important data area in java and a data area shared by threads. Almost all objects and arrays need to be allocated memory in the heap, which is also the main area for managing the garbage collector. A more detailed heap division can also be divided into the new generation and the old generation. The new generation can also be divided into an Eden space and two terravor spaces (Form into VOR and To writable VOR ). The heap can allow non-consecutive physical memory spaces, but the logical memory space is continuous.

The method area (also known as non-heap) is shared by threads to store data such as class information, constants, static variables, and compiled code of the real-time compiler loaded by virtual machines.

There is a very important subarea in the method area: the runtime frequent volume pool, which is used to store the literal volume and symbolic reference generated by compilation, and is directly reflected as the constant_pool data item in the class bytecode file.

A more specific example is as follows:

package com.demo;public class Empty {    static int value = 10;     public static void main(String[] args) {        // TODO Auto-generated method stub    }}

Parse the bytecode file with javap-verbose and intercept the information of the Constant pool segment. This is actually the static file display form of the Constant pool.

From the above, we can see a total of 24 items in the constant pool (counting from 1), some of which are familiar with literal and symbolic references: java/lang/Object, [Ljava/lang/String;: String-type array descriptor, I: integer descriptor, <clinit>: class initialization method, <init>: constructor, this, main, Code: the Code attribute of the Attribute Table, the Code of the method body is archived under this attribute after compilation, and so on. These will be referenced in other data items in the bytecode file.

1.2 Object Access

Two Methods for Object Access: using a handle and using a direct pointer.

Sun HotSpot uses direct pointers to access objects.

1.3. Several important memory Parameters

-The maximum value of Xmx Java Heap. The default value is 1/4 of the physical memory. The optimal value depends on the physical memory size and other memory overhead in the computer;
-The initial value of Xms Java Heap. It is best to set-Xms and-Xmx to the same value on the Server JVM. The default value can be retained on the JVM of the development and testing machine;
-The size of the Xmn Java Heap Young area. If you are not familiar with it, keep the default value;
-The Stack size of each Xss thread. It is best to keep the default value if you are not familiar with it;

-XX: PermSize: Non-heap memory initially allocated by JVM
-XX: MaxPermSize: specifies the maximum non-heap memory that can be allocated by the JVM, which is allocated on demand.

2. Automatic Memory Management

Java's automatic memory management includes two aspects: allocating memory to objects and recycling the memory allocated to objects (garbage collection ).

Garbage collection and automatic memory allocation do not come from java. In fact, Lisp is the first language to use this technology.

2.1. Garbage Collection

2.1.1 Determination of object survival

There are two algorithms for determining whether an object is alive: The reference counting algorithm and the root search algorithm.

Reference Counting Algorithm

Set a reference counter for each object. Whenever a reference is made to this object, the counter value is incremented by 1. When the reference fails, the counter value is reduced by 1, when the counter value is 0, it indicates that the object is no longer used and should be recycled.

This algorithm is easy to implement. Generally, it is highly efficient to judge, but it cannot judge the situation of loop reference. For example, the member variable of object A references object B, and the member variable of object B references object A. Objects A and B constitute A circular reference, although the reference counter of objects A and B is not 0, they may already be useless objects. In this case, the reference counter algorithm has blind spots and the algorithm is invalid. Java virtual machine does not adopt this algorithm either.

Root Search Algorithm

By using a series of objects called "GC Root" as the starting point, you can search down from these nodes and find the path that you have traveled is called a reference chain, when there is no reference link between an object and GC Root (from the graph theory perspective, GC Root is inaccessible to this object), the object will be recycled if it is unavailable.

So what objects can be used as GC Root? The following types can be used as GC Root objects:

1) Objects referenced in the Virtual Machine stack (local variable table;

2) Objects referenced by static variables in the method area;

3) Objects referenced by constants in the method area;

4) Objects referenced in the native method stack.

Reference extension:

After JDK1.2, the reference concept is expanded to form four different references: strong reference, soft reference, weak reference, and virtual reference. The reference intensity decreases in turn.

It is worth noting that:

The real death of an object actually requires at least two tags. After going through the Root search algorithm, it is found that the object is not connected to the GC Root. At this time, the first tag occurs, then a "whether to execute finalize ()" decision will be made. If it is determined that the finalize () method needs to be executed, the virtual machine will call finalize () later (), this is the second mark.

The finalize () method of an object can only be automatically called once by the system. finalize () is the last chance for the object to escape from death.

2.1.2 garbage collection Algorithm

There are four major garbage collection algorithms: tag-clearing algorithm, replication algorithm, tag-sorting algorithm, and generation-based collection algorithm.

Mark-clearing algorithm:

The tag-clearing algorithm is a basic collection algorithm, which is divided into two stages: tag and clear. However, there are two main disadvantages: low efficiency and easy to generate memory fragments.

Copy algorithm:

The replication algorithm can solve the efficiency problem. The basic idea is that half of the memory capacity is used to act as a "backup" for each other. when half of the memory capacity is used up, then, the surviving objects are directly copied to the other half of the space, and all the original half of the space is cleared, which serves as a "backup" again. This mechanism does not need to consider the impact of memory fragmentation.

But there are more than that.

In fact, the actual situation is divided according To, 8 refers To the Eden space, two 1 refers To the same size of the same vor space (From two VOR and To another VOR ), every time you use the Eden space and one of the two vor spaces, when garbage collection is performed, copy the objects that are currently in use in the Eden and other vor spaces to another idle vor space, at the same time, the Eden and vor space used just now are cleared. Of course, there is a memory guarantee mechanism here. Based on this mechanism of copying objects, it is not difficult to see that when the survival rate of objects is relatively low, the cost of this algorithm is very small and the effect is very good.

Tag-sorting algorithm:

The tag-sorting algorithm mainly targets objects with a high survival rate and only a few objects are recycled. In this case, there is no need to move all objects, and only a few objects to be recycled need to be released, at the same time, the remaining object space is adjusted so that no serious memory fragments occur.

Generation and recycling algorithms:

The generational collection algorithm divides the heap into the new generation and the old generation based on the length of the object survival cycle, and uses different algorithms.

The new generation refers to areas with short object storage periods. A large number of objects are recycled in garbage collection, which is suitable for the use of replication collection algorithms. The old generation refers to areas with long object storage periods, where a large number of objects will survive in garbage collection, it is applicable to the tag-sorting algorithm.

Differences between Minnor GC and Full GC:

New Generation GC (Minnor GC): The garbage collection action occurs in the new generation. The object storage period is short, and the Minnor GC is very frequent and fast.

GC (Major GC/Full GC) in the old age: Garbage collection occurs in the old age. The object storage period is long, and the Major GC is much slower than the Minnor GC (more than 10 times ).

2.2. Memory Allocation

Memory allocation principles:

1. objects are preferentially allocated in Eden space.

2. large objects directly enter the old age (objects with continuous memory space, typical long strings or arrays ).

3. Long-lived objects will enter the old age.

Objects in the same vor space do not survive Minnor GC in turn, and their Age counters (Age) Add 1. When the cumulative increase to the default value of 15, they are promoted to the old Age.

4. But in fact, as long as the sum of all objects of the same age in the region vor space is greater than that of the region vor space, objects of the same age will enter the old age, you do not need to wait for a threshold of age.

The role of the memory guarantee is that the new generation of garbage collection has little effect, and a large number of objects survive. At this time, the other slave vor space that acts as a "backup" cannot accommodate, objects that cannot be accommodated will directly enter the old age. But there is another question to consider: Can the Old Age accommodate the new generation of objects? (Note: it is impossible to know how many objects will survive before Minnor GC is performed on the New Generation)

If the capacity is insufficient, a Full GC operation is required in the old age to free up space. Therefore, here we can only use an average value of the object capacity that was previously reclaimed and promoted to the old age as an empirical value to compare the remaining space in the old age to determine whether Full GC is required. However, even so, in the sense of probability, it is inevitable that the guarantee fails.

3. class file structure

The class file is in bytes and organizes data in a pseudo structure similar to the structure of the C language. This pseudo structure has only two data types:

1) unsigned number (u1, u2, u4, u8, which belongs to the basic data type)

2) tables (of the composite data type)

The basic data type can be combined to form a table. The table and the table can be nested to form a multi-dimensional table. In fact, the entire class file can be considered as a table, this table is nested with different tables.

The class consists of the following content:

Although this part of the content is boring and requires meditation and patience, when we need to use javap to parse the bytecode instructions of the class file to explore the principle of a deeper language, this part of knowledge is undoubtedly necessary.

In my opinion, the most important thing is the method table and the constant pool. The constant pool is important because it is a class file and other data items (mainly field tables, method tables, and attribute tables) the data type with the most associations and interactions. The reason why a method table (including the Attribute Table) is important is that, when analyzing bytecode files, you often pay more attention to the display of bytecode after the method bodies in the java source files are compiled, this part is more accurate in the "Code" attribute of the embedded Attribute Table of the method table.

Constant pool:

The constant pool is actually a complex data item in the class file, because the constant pool can store 11 different constants, and these 11 different constants are actually Composite data types (table structure data, they all have their own structures (in fact, their structures are similar ). To sum up, the constant pool itself is a table, and each item in the table is also a table. Therefore, we can think that the constant pool is a two-dimensional table structure.

Several points need to be summarized:

1. The constant pool starts counting from 1, and 0th items have special significance.

Constant pool:#1 = Class #2 // com/demo/TestDispatch#2 = Utf8 com/demo/TestDispatch

2. The constant pool mainly stores Literal and Symolic References ).

Symbol references mainly include:

1) Fully Qualified Name)
2) field name and Descriptor (Descriptor)
3) method name and Descriptor

Field table:

There are three concepts in the field table (field_info): "Full qualified name", "simple name", and "descriptor"

Full qualified names are easy to understand. Simple names are methods or field names that remove type and parameter modifier.

The descriptor is a little more complex. Pay attention to the descriptor (B, C, D, F, I, J, S, Z) of basic data types in 8 ), void Descriptor (V), object type descriptor (L), array type descriptor ([) and method Descriptor (describe the parameter list first, put in, description of the return value type). These are the prerequisites for reading bytecode files.

For attribute tables (attribute_info), the focus is on the Code attribute, involving the bytecode part of the method body. The LineNumberTable and LocalVariableTable attributes are fine.

4. class loading process

Class has seven stages in its lifecycle: Loading, verification, preparation, parsing, initialization, use, and uninstallation.

The VM specification does not specify the loading time of classes, but specifies four scenarios that actively reference classes. In these four scenarios, class requirements are initialized:

1) The four bytecode commands "new", "getstatic", "putstatic", and "invokestatic" are encountered. (Note that the newarray command only triggers the initialization of the array type, but does not cause initialization of the related type, for example, new String [] will only directly trigger the initialization of the String [] class, that is, the initialization of the class [Ljava. lang. string initialization, but will not directly trigger the initialization of the String class), if the class has not been initialized, You need to initialize it first. The most common Java code scenarios for generating these four commands are:

• When an object is instantiated using the new keyword;
• When reading or setting a static field of a class (modified by final, except for the static field where the compiler puts the result into the constant pool;
• Call a static method of a class.

2) When using the java. lang. reflect package method to call the class reflection, if the class has not been initialized, it needs to be triggered first.
3) When initializing a class, if the parent class has not been initialized, you must first trigger the initialization of the parent class.
4) when the VM starts, you need to specify a main class to be executed (the class containing the main () method). The virtual opportunity first initializes the main class.

The rest of the scenarios are called passive references and classes are not initialized.

4.1. class loading process

The loading phase mainly includes:

1) Get the binary byte stream defining this Class by using the full qualified name of a Class (it does not indicate that you want to get it from a Class file, but can use other channels, such: networks, dynamic generation, databases, etc );
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 that represents this Class in the memory (for hot spot virtual, it is the method area) and serve as the access portal for various data of this Class in the method area;

Main Tasks in the verification phase include: File Format verification, metadata verification, bytecode verification, and symbol reference verification.

Preparation phase:In this phase, you need to pay special attention to allocating memory for class variables and assigning zero values (this zero value refers to the default values of various types). class variables are assigned values for the first time in this phase. At the same time, the class variables modified by final are directly assigned to the program set value rather than zero value.

Work in the parsing phase: Replace the symbol reference in the constant pool with a direct reference.

Why is there such a parsing process?

Because the process of compiling a java source file into bytecode does not involve links in the "Compilation" process in the general sense, therefore, the symbolic references in the constant pool of the compiled bytecode file are not mapped to the memory layout of the VM, And the referenced targets are not necessarily loaded into the memory, however, the execution of bytecode commands must be associated with such a conversion process.

The parsing mainly targets Class or interface (both Class), field (Fieldref), Class Method (Methodref), and interface method Class symbol reference for parsing.

Initialization phase:

The initialization phase is the last phase of class loading, which is to set the initial value for the class variable according to the program code intent (that is, to start the real execution of the Code to assign the initial value, that is, the execution constructor <clinit> ).

In this phase, pay special attention to the Generation Principle of <clint> (the process of collecting class variables and static statement blocks) and the difference with the class Constructor (<init> constructor.

The <clint> constructor call may not be seen in the parsing of bytecode files through javap, but it is actually in the constant pool of any class file (of course, class members or static code blocks need to be defined) you can find the <clint> and <init> symbol references.

4.2 class loaders

Different from the source code, the virtual machine has a loader. In this case, the loader instance and the class permission name are used to uniquely identify a class.

From the perspective of whether the loader is independent from the virtual machine, it can be divided into the start loader (a part of the Virtual Machine) and other loaders (independent from the virtual machine ).

There are three types of loaders:

1) BootstrapLoader: it is a Class Loader implemented using local code. It is responsible for loading the Class Libraries under <Java_Runtime_Home>/lib to the memory (such as rt. jar ). Since the bootstrap loader involves the local implementation details of the virtual machine, developers cannot directly obtain the reference of the bootstrap loader, so they cannot directly perform operations through the reference.
2) extended Class Loader: It is implemented by Sun's ExtClassLoader (sun. misc. Launcher $ ExtClassLoader. It loads <Java_Runtime_Home>/lib/ext or the class library specified by the system variable java. ext. dir to the memory. Developers can directly use the standard extension class loader.
3) system class loader or application Class Loader (AppClassLoader): Implemented by Sun's AppClassLoader (sun. misc. Launcher $ AppClassLoader. It is responsible for loading the class library specified in the system classpath to the memory. Developers can directly use the system class loader.

There is a parent-child relationship between them. From the code perspective, the parent-child relationship is reflected by the parent instance attributes.

A parent instance attribute is clearly defined in the source code of the abstract class java. lang. ClassLoader,

    private ClassLoader parent;

Launcher $ ExtClassLoader and Launcher $ AppClassLoader both inherit URLClassLoader. URLClassLoader inherits SecureClassLoader, while SecureClassLoader is the direct implementation subclass of ClassLoader.

From the source code of the loadClass (String name, boolean resolve) method of the abstract class java. lang. ClassLoader, you can easily view the operation process of the parent-child delegate model:

Protected synchronized Class <?> LoadClass (String name, boolean resolve) throws ClassNotFoundException {// First, check if the class has already been loaded Class c = findLoadedClass (name); if (c = null) {// if the class is not loaded try {if (parent! = Null) {// its parent loader is not BootstrapLoader c = parent. loadClass (name, false);} else {// its parent loader is BootstrapLoader c = findBootstrapClass0 (name);} catch (ClassNotFoundException e) {// The parent loader cannot be loaded, only loaded by yourself // If still not found, then invoke findClass in order // to find the class. c = findClass (name) ;}}if (resolve) {resolveClass (c) ;}return c ;}

A direct benefit of the parent-child delegation model is that it ensures the hierarchical relationships identified in the java type system. More specifically, such as Object. the class bytecode file exists in <Java_Home>/lib/rt. in the jar package, the parent-parent loader takes precedence. Each time you load the Object class, you can determine that it must be loaded by BootstrapLoader. On the one hand, the Object in other places. the class will not be loaded by BootstrapLoader. On the other hand, the other two class loaders normally do not have the opportunity to load this Object. so as to ensure the certainty of the loading status of the basic class library, and ensure the stability of the java program running developed on the basis.

5. execution engine

5.1 method call

Note: The java compilation process does not involve links in the compilation phase in the general sense. method calls are different from method execution. The purpose of method calls is to determine a specific version of a method.

The Java virtual machine provides instructions for calling four methods:

1. invokestatic: Call static methods

2. invokespecial: Call the constructor method <init>, private method, and parent class method.

      20: invokespecial #49                 // Method "<init>":()V

3. invokevirtual: Call all Virtual Methods

4. invokeinterface: Call an interface method and determine the object to implement this interface at runtime.

Methods (class methods, constructors, private methods, and parent class methods) that can be called by the invokestatic and invokespecial commands and Methods Modified by final are called non-virtual methods, other methods are virtual methods.

All non-virtual methods can determine the version of the method in the parsing phase of class loading, and the symbolic reference will also be resolved to a direct reference. The method call in this process is called a resolution call.

5.2 Static and Dynamic assignment

Resolution call must be a static process, and the dispatch call may be static or dynamic. It can also be divided into single dispatch and multi-dispatch from another perspective. Static Single-assignment, static multi-assignment, dynamic single-assignment, and dynamic multi-assignment can be combined in two cases.

A typical application of static dispatch call is method overloading.

Because the subclass instance in java can be copied to the parent class variable, there may be a case where the static type of a variable is different from the actual type.

For example (the premise here is Man extends Human ):

Human humanA = new Man();

HumanA's static type is Human, while the actual type is Man.

Depending on the static type to determine whether the method executes version assignment is called static assignment. Static allocation occurs in the compilation phase. The Compiler determines the specific version of the Method Based on the static type of the parameter rather than the actual type, this can be verified by calling the command to view the compiled bytecode.

Test code:

package com.demo;public class TestDispatch {    static abstract class Human{}    static class Man extends Human{}    static class Woman extends Human{}    public void say(Human huamn){        System.out.println("human say");    }    public void say(Man man){        System.out.println("man say");    }    public void say(Woman man){        System.out.println("woman say");    }    public static void main(String[] args) {        // TODO Auto-generated method stub        Human humanA = new Man();        Human humanB = new Woman();         TestDispatch td = new TestDispatch();        td.say(humanA);        td.say(humanB);    }}

The bytecode command used to intercept the main method part of the above test code:

public static void main(java.lang.String[]);  Code:     0: new           #43                 // class com/demo/TestDispatch$Man     3: dup     4: invokespecial #45                 // Method com/demo/TestDispatch$Man."<init>":()V     7: astore_1     8: new           #46                 // class com/demo/TestDispatch$Woman    11: dup    12: invokespecial #48                 // Method com/demo/TestDispatch$Woman."<init>":()V    15: astore_2    16: new           #1                  // class com/demo/TestDispatch    19: dup    20: invokespecial #49                 // Method "<init>":()V    23: astore_3    24: aload_3    25: aload_1    26: invokevirtual #50                 // Method say:(Lcom/demo/TestDispatch$Human;)V    29: aload_3    30: aload_2    31: invokevirtual #50                 // Method say:(Lcom/demo/TestDispatch$Human;)V    34: return

We can see that the call parameters of the invokevirtual command are the 26th constants of the constant pool, and the comments indicate that the constant is actually a symbolic reference of TestDispatch $ Human. say (Human human Human.

Dynamic dispatch reveals the essence of method rewriting (or overwrite.

Invokevirtual Command Parsing process (multi-state search process ):

1. Find the actual type of the object pointed to by the first element at the top of the operand stack, and write it as C;

2. If the method in Type C that matches the simple name described in the constant is found, the access permission is verified. If the method is passed, the direct reference of the method is returned, and the search is over; if it does not pass, java is returned. illegalAccessError is abnormal;

3. Otherwise, perform Step 1 search and verification for each parent class of C from the bottom up according to the inheritance relationship;

4. If no proper method is found, a java. lang. AbstractMethodError exception is thrown.

Java Virtual Machine commands are stack-based commands, but some commands also contain parameters (such as invokevirtual and invokespecial). Compared with register-based instruction sets, stack-based instruction sets are easier to transplant, however, the execution speed is a little slow, and the number of commands is more.

6,Syntactic sugar

Common syntax sugar in java is mainly generic, variable-length parameters, Automatic Disassembly box, and loop traversal (foreach.

Therefore, the general principles of java and C # are essentially different. java generics only exist in the source code. After compilation, the generic information will be erased, in bytecode, it is converted to the native type. After compilation, ArrayList <Integer> and ArrayList <String> are converted to the same ArrayList type. Therefore, java generics are syntactic sugar, is a pseudo-generic type.

Note: generics are not necessarily implemented by syntactic sugar. For example, C # generics are directly supported by CLR.

However, generic erasure also brings some strange phenomena:

    public static int test(ArrayList<String> list1){        System.out.println("list1");        return 1;    }    public static float test(ArrayList<Integer> list2){        System.out.println("list2");        return 1.0f;    }

The above two methods with the same name can be compiled and executed normally.

The syntax sugar for automatic splitting, packing, foreach traversal, and variable length parameters is as follows:

Package com. demo; import java. util. arrays; import java. util. iterator; import java. util. list; public class TestSSugar {public static void main (String [] args) {// TODO Auto-generated method stub List <Integer> list = Arrays. asList (1, 2, 3, 4); int sum = 0; for (int I: list) {sum + = I ;} /* the above Code is equivalent to the following basic syntax structure code * // List <Integer> list = Arrays. asList (new Integer [] {// The variable length parameter is de-syntactically sugar, which is actually an array // Integer. valueOf (1), // automatic packing actually calls the valueOf () method // Integer. valueOf (2), // Integer. valueOf (3), // Integer. valueOf (4),}); // int sum = 0; // for (Iterator localIterator = list. iterator (); localIterator. hasNext ();) {// foreach traversal. The de-syntactic sugar actually calls the Iterator interface // int I = (Integer) localIterator. next (); // sum + = I; //} System. out. println (sum );}}

End ~~~

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.