"In-depth understanding of the Java Virtual Machine" (third edition) reading notes (five): Chapter VII VM class loading mechanism

"In-depth understanding of the Java Virtual Machine" (third edition) reading notes (five): Chapter VII VM class loading mechanism


Reading notes (d) of the Class A recorded file storage format, Chapter VII was talking about is how to load these Class files, as well as what happens after loaded into the virtual machine. Line and finished this chapter, go to b stand to see a video about the JVM class loading, eating better estimate the effect ...

Before the start of the text, to give an account of what is called the class loading mechanism of the virtual machine: Java virtual machine to load data that describes the classes from Class file into memory, and data validation, parsing and conversion initialization, eventually forming the type of Java class loading mechanism can be used directly in virtual machines, this process is the virtual machine.

Class loading time

Starting a type of virtual machine is loaded into memory, up to unload the memory, will go through the entire life cycle load (Loading), verification (Verification), preparation (Preparation), analytical (Resolution ), initialization (the initialization), using (the using) and unloading (unloading) seven stages in which verification, preparation, parsing three portions collectively connected (Linking).

Loading, validation, preparation, initialization and unloading sequence five stages is to determine the type of load step by step process must begin in this order, not necessarily the parsing stage. It can begin after the initialization phase.

"Java Virtual Machine Specification" There are strict rules and only six cases have the class immediately 初始化(load, validate, prepare natural need to start before this):

  • Encounter new, getstatic, putstatic, invokestatic 4 bytecode instructions that time, if the type had not been initialized, the initialization phase which need to be punished, it is possible to generate four instructions have typical scenario:

    • Use the new keyword to instantiate an object when
    • Read or set a static field type (the final modification, the compiler has been the result into the constant pool except for static fields) when
    • Call the static method of a type of time
  • When using java.lang.reflect package approach to reflect the type of call, if the type is not been initialized, you need to trigger its initialization.

  • When the class initialization time, if we find the parent class has not initialized, you need to trigger initialization of the parent class

  • When the virtual machine starts, the user needs to specify a main class to be executed, the virtual machine to initialize this master class

  • When an interface defines the default method JDK8 new entrants, if the interface implementation class initialization occurred, that this interface is to be initialized before it.

  • If a final analysis result java.lang.invoke.MethodHandle Examples REF_getStatic, REF_putStatic, REF_invokeStatic, REF_newInvokeSpecial handle four types of methods, and this method handle class corresponding to not been initialized, initialization is required to trigger it.

    Interface also has the loading process, and the class loading process is not the same, the difference between the local interfaces and classes are six kinds of the aforementioned "one and only" initialization required to trigger the third scenario: when a class initialization, which requires all the parent class has been initialized, but an interface during initialization, the interface does not require the parent to complete all initialization, only in real time using the parent interface will be initialized .

Class loading process

load

In the loading process, JVM mainly to do three things: First, to get the definition of such a binary byte stream through a fully qualified name of the class; then will represent the byte stream of static storage structure into a run-time data structure area method; in memory the last generates a representative of this class java.lang.Class objects, a method for accessing the various data entry area of ​​this class.

  • If the array type component (Component Type, refers to an array type remove a dimension, attention and separate the front element type region) is a reference type, then the recursive use of the present loading section to load the defined component types, array will be identified on the loading type of the component class loader class name space.
  • If the component type is not an array reference type (e.g., int [] array for the component type int), Java virtual machine is the marked array associated with the boot class loader .
  • Array class consistent with the accessibility of its accessibility component type , if the component type is not a reference type, its accessibility array class will default to public , all classes and interfaces can be accessed.
  • After the loading stage, Java Virtual Machine external binary byte stream according to the format stored in the virtual machine is set in a process zone, the method area data storage format implemented entirely defined by the virtual machine itself, "Java Virtual Machine specification "specific data structure for this area is not predetermined. After proper placement type data area method, will instantiate an object of class java.lang.Class in the Java heap memory, the object as an external interface program access method of the data type area.
  • Loading phase and the connection phase of the operation part (e.g., part of the file format byte code verification operation) is carried out intersecting, the loading phase has not been completed, the connection phase may have started, but they caught in the loading stage of the operation, is still a connection part of the stage, the start time these two stages remained fixed sequence.
verification

Class information to ensure that the file contains the byte stream meets all constraints require "Java Virtual Machine Specification", to ensure that information is treated as the code to run virtual machines without jeopardizing their own safety.

ready

Preparation phase is formally defined in the class variables (ie, static variables, static variables modified) allocate memory and set the stage class variable initial values. This time memory allocation includes only class variables, and does not include the instance variables, instance variables will be assigned along with the object when the object is instantiated in the Java heap.

Resolve

Java virtual machine constant pool of symbolic references to the process of replacing direct references.

initialization

Initialization phase is performed class constructor <clinit>()process approach. <clinit>()Methods are not programmers write Java code directly, it is automatically product Javac compiler.

<clinit>()It is collected automatically by the compiler class for all classes and static variables assignment statement block operation (static {} block) statements merger sequentially compiler is collected by the statement determine the order of appearance of the source file, block static statements can only access to the static variables defined in a block of statements before, the definition of variables behind it, in front of a static blocks can be assigned, but can not be accessed.

<clinit>()The method of the class constructor (i.e., in the instance of the virtual machine is configured in the perspective <init>()method) different, it does not explicitly call parent class constructor, Java virtual machine to ensure that the subclass's <clinit>()method before execution of the parent class <clinit>()() method has finished executing . Therefore, in the first Java virtual machine <executed <clinit>()type of the method must be java.lang.Object. Statically defined parent class statement block takes precedence subclass variable assignment.

If a class is not a static block of statements, there is no assignment of the variable, then the compiler can not generate the class <clinit>()method.

Interface block static statements can not be used, but there is still initialized variable assignment, and therefore generates the same class interface <clinit>()methods. However, the difference is the class interface, implements the interface <clinit>()does not require to execute the parent interface <clinit>()method, since only the parent when the variable defined in the interface is used, will be initialized parent interface. Further, the interface implementation class that implements the interface is not the same when initialization <clinit>()method.

Java virtual machine must ensure that a class <clinit>()method is synchronized correctly locked in a multi-threaded environment , if multiple threads to initialize a class, then there will only be one thread to perform this class the <clinit>()method, other threads are blocked need to wait until the active thread is finished <clinit>()method.

Class loader

Class loader class hierarchy is divided, OSGi, hot deployment, code encryption and other fields shine, Java technology has become an important cornerstone of the system, which was originally to meet the needs of design Applet now Applet eliminated (browser aspects).

Class and class loader

For any class, must be jointly established by the class loader that loaded it and the class itself with its uniqueness in the Java virtual machine, class is to compare two "equal" only in these two classes are made under the premise makes sense to load the same class loader, otherwise, even if these two classes a class from the same file, is loaded with a Java virtual machine, as long as the class loader to load them different, that these two classes will surely not equal.

This concept is the first time I saw the code to reproduce Chou Chou.

public class ClassLoaderTest {

	public static void main(String[] args) throws Exception {

		ClassLoader myLoader=new ClassLoader() {
			@Override
			public Class<?> loadClass(String name) throws ClassNotFoundException {
				try {
					String filaName=name.substring(name.lastIndexOf(".")+1)+".class";
					InputStream is=getClass().getResourceAsStream(filaName);
					if(is==null){
						return super.loadClass(name);
					}
					byte[] b=new byte[is.available()];
					is.read(b);
					return  defineClass(name,b,0,b.length);
				} catch (IOException e) {
					throw  new ClassNotFoundException(name);
				}
			}
		};

		Object obj=myLoader.loadClass("exam.offer.day05.ClassLoaderTest").newInstance();

		System.out.println(obj.getClass());
		System.out.println(obj instanceof exam.offer.day05.ClassLoaderTest);
	}
}

The result:

class exam.offer.day05.ClassLoaderTest
false

The above code is to construct a simple class loader, which loads class and with a exam.offer.day05.ClassLoaderTest and instantiated.

Java virtual machine exist ClassLoaderTest two classes, one is by the application of virtual machine class loader loaded, the other is by the class loader to load our custom, though they come from the same class file, but in the Java virtual machine is still two mutually independent classes, the results do type checking natural object belongs to false.

Parent delegation model

From the point of view of the Java virtual machine, there are only two different class loader, a boot class loader is (BootstrapClassLoader), using the C ++ implementation, part of a virtual machine; and one is that all of the other class loader, implemented by Java, exist independently outside the virtual machine, and all derived from the abstract class java.lang.ClassLoader.

The parent class loading delegation model hierarchy as shown below:

img

Boot class loader (Bootstrap Class Loader): responsible for loading stored at <JAVA_HOME> \ lib directory, or is -Xbootclasspathspecified by the parameters stored in the path, and the Java virtual machine is capable of identifying library loaded into memory the virtual machine.

Extension class loader (Extension Class Loader): This class is the class loader sun.misc.Launcher $ ExtClassLoader implemented in the form of Java code. It is responsible for loading <JAVA_HOME> \ lib ext directory or are specified java.ext.dirs system variables path \ all of the libraries.

Application class loader (Application Class Loader): This class loader is implemented by sun.misc.Launcher $ AppClassLoader. Since the application class loader is getSystem-ClassLoader ClassLoader class return value () method, so that some occasions also called "system class loader." It is responsible for loading all the libraries on the user class path (ClassPath).

Parent delegation model of working process is: if a class loader loads the class received a request, it first does not own to try to load this class, but to delegate this request to the parent class loader to complete each level of the class loader is true, so all load requests should be sent to the final top-level boot loader class, only when the parent loader feedback they can not complete the loading request (its search when required class) is not found, the child loader will try to complete their own load.

Why parents delegate model? Safety, can avoid duplication of core classes to load and avoid being tampered with . If we wrote called java.lang.Object class in ClassPath years, then the system will appear in a number of the Object class, but uses a delegation model parents, although this class can be compiled normally, but can not be loaded to run. Because the first is the most top class java.lang.Object class loader loading system, the ultimate custom class loader can not load the java.lang.Object class.

Specifically looking at the source code, source code and comments contrast with the look, easier to understand the entire work process.

    protected Class<?> loadClass(String name, boolean resolve)
        throws ClassNotFoundException
    {
        synchronized (getClassLoadingLock(name)) {
            // First, check if the class has already been loaded
            Class<?> c = findLoadedClass(name);
            if (c == null) {
                long t0 = System.nanoTime();
                try {
                    if (parent != null) {
                        c = parent.loadClass(name, false);
                    } else {
                        c = findBootstrapClassOrNull(name);
                    }
                } catch (ClassNotFoundException e) {
                    // ClassNotFoundException thrown if class not found
                    // from the non-null parent class loader
                }

                if (c == null) {
                    // If still not found, then invoke findClass in order
                    // to find the class.
                    long t1 = System.nanoTime();
                    c = findClass(name);

                    // this is the defining class loader; record the stats
                    sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
                    sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
                    sun.misc.PerfCounter.getFindClasses().increment();
                }
            }
            if (resolve) {
                resolveClass(c);
            }
            return c;
        }
    }
Destruction parents delegation model

There are three times the entire damage.

-> The first damage : occurs before the parent delegation model appears. Parent delegation model is emerging after JDK1.2, but user-defined class loader has been in existence, so the parent delegation model for compatibility with existing code, you can only add a new protected method findClass in java.lang.ClassLoader in () possible to override this method, the guide prepared by the user class loader logic, rather than loadClass (). If override the findClass (), and then carrying out similar class and a class loader that part of the code, can be found in the printing result is true. Testing can look for examples -> How to destroy parental delegation model

-> Second destroyed : the model itself defects caused parents appoint a good solution to the same problem underlying class each class loader (the base class loader of the upper loading), base class is called "foundation" because they are always invoked as an API user code, but things are often not absolutely perfect.

If you have to call the base class back to the user code, then the What to do?

A typical example is the JNDI service, JNDI is now standard Java service, its code from the boot class loader to load (into them in JDK1.3 when rt.jar), but the JNDI the purpose is to centralize management resources and look, it needs to implement and deploy the code to call JNDI interface provider in ClassPath applications by independent vendors, but the boot class loader can not "know" these codes.

To solve this problem, Java design team had introduced a less elegant design: the thread context class loader (Thread Context ClassLoader). This class loader can be set by setContextClassLoader () method java.lang.Thread class has not been set when you create a thread, he will inherit from a parent thread, if you have not set globally through the application , then the class loader is the default application class loader.

With loader thread context, the JNDI service can use it to load the SPI code is required, which is the parent class loader class loader request to complete the sub-class loading operation, the actual behavior of this the thing is to get through the parent delegation model hierarchy to reverse using a class loader has actually violated the general principles parent delegation model, but also helpless. All Java loading operation involves basically the SPI this way, for example the JNDI, the JDBC , the JCE, JBI JAXB and the like.

-> Third destruction : the pursuit of the program because the user dynamics caused, here called "dynamic" refers to the current some very "hot" noun: hot code replacement module hot deployment, the short answer that is to say without restarting the machine, as long as the deployment will be able to use.

To JDBC, for example, examples of parents delegation model is destroyed elaborate. Native JDBC type is placed in the package rt.jar by BootstrapClassLoader loaded, the JDBC Driver class need to dynamically load different types of databases Driver class, and mysql-connector-.jar Driver class is the users write their own code that starts the class loader certainly can not be loaded, since it is the code I have written, it would need to be loaded by the application class started class by Thread Context ClassLoader can solve this model has been delegated parents a breach of the smooth loading.

Java modular system

JDK9 modular system is introduced. If the modular encapsulation enabled, the module can declare explicitly depend on other modules , so the Java virtual machine will be able to start verifying the application development phase to set a good dependencies are complete at runtime , that if missing It failed to start directly, thus avoiding a run large part due to the type of dependence caused by abnormal.

The class loader Modular

1. The extension class loader (Extension Class Loader) substituted class loader platform (Platform Class Loader)

2. The platform class loader and application class loader are no longer derived from java.net.URLClassLoader

Published 58 original articles · won praise 5 · Views 6240

Guess you like

Origin blog.csdn.net/weixin_40992982/article/details/104055126