JVM – Class loader

What class loading does:

The virtual machine loads the data describing the Class from the Class file into the memory, and verifies, converts, and initializes the data to form Java types that can be directly used by virtual machines. This is the Class loading mechanism of virtual machines.

Class loading timing (when to do it) :

  1. Creates an object for the class
new Demo();
Copy the code
  1. Access a static variable of a class or interface, or assign a value to a static variable and call a static method of the class
1. Demo.GET_STATUS_VALUE = 2;
2. Integer i = Demo.GET_STATUS_VALUE
3. Integer i = Demo.getStatusValueMethod();
Copy the code
  1. reflection
Demo.class.newInstance();
Copy the code
  1. Initialize a subclass of a class
public class Parent(){}
public class Children() extends Parent{}
public class Demo(){
    public static void main(String[] args) throws Exception {
        Demo demo = new Children();
        // 会加载Parent后加载Children
    }
}
Copy the code
  1. The Java virtual machine is indicated as a startup class when it starts
java[-options] Demo
Copy the code
  1. JDK7 began to provide dynamic language support Java. Long. Invoke. Analytical results REF_getStatic MethodHandle instance, REF_putStatic, REF_invokeStatic All Java virtual machine implementations must load == in the “first active use” of a Java program for each class or interface

Class loading process (how to do it)

Graph LR Load --> Connect connect --> initialize Initialize --> Use Use --> uninstall

loading

The loading process mainly accomplishes the following three things:

  1. Use the fully qualified name of a class to get the binary name that defines the class (forname)
  2. == converts the static stored result represented by this byte stream into the runtime data structure of the method area ==
  3. == Generates a java.lang.class object representing the class in memory as an access point to the class’s various data in the method area ==
  • Array loading:
    1. If the array’s internal element type is a reference type, the component type is recursively loaded in the basic manner, and the array is identified in the class namespace of the classloader that loaded the component type
    2. If the array’s internal element type is not a reference type (such as an int[] array), the Java virtual machine will mark the array as associated with the == bootstrap classloader ==.
    3. The visibility of array classes is the same as the visibility of the inner element types. If the component type is not a reference type, the visibility of array classes defaults to public.
  • After the load phase is complete, the external binary byte stream is stored in the method area in the format required by the virtual machine. It then instantiates an object of the Java.lang. Class Class in the method area (meta-space), which acts as an external interface for the program to access the data of these types in the method area.

The connection

Validation preparation parsing

Graph LR Validation --> Prepare prepare --> parse

validation

The purpose of this phase is to ensure 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

  1. Text format validation
  2. Metadata validation
  3. Bytecode verification
  4. Symbolic reference

To prepare

This stage allocates memory for class variables and sets their initial values. == Class variables (static)== class variables (static)== class variables (static)== class variables (static)== class variables (static)== class variables (static)== class variables (static)== class variables (static)== class variables (static)== instance variables (instance variables)==

public static int value=123;
Copy the code
  • The initial value of that variable after the preparation phase is 0 instead of 123.

The zero value of the data base type

The data type Zero value The data type Zero value
int 0 boolean flase
long 0L float 0.0 f
short (short)0 double 0.0 d
char ‘\u0000’ referrnce null
byte (byte)0
  • If the variable is modified with final then the value of the variable is given the true initial value in the preparation phase. For example:
public static final int value=123;
Copy the code
  • The initial value of that variable after the preparation phase is 123 instead of 0

Initialize the

Class variables and other resources are initialized (with true initial values) according to a subjective plan that the programmer has made through the program. The initialization phase is the execution of the class constructor Clinit () method.

clinit()

Is by the compiler automatically collect all kinds of variable assignment in class action and static blocks (static {} block) of the statement in merger, the compiler collection order is by the statement in the source file, determined by the order of the static block can only access to the definition in the static block before the variable, defined in the variable after it, The previous static block can be assigned, but not accessed.

  • A demo explaining the above code:
public class Demo { static int i = 1; static final int i2 = 1; private static Demo demo = new Demo(); static int j = 2; static final int j2 = 2; Public static void main(String[] args) throws Exception {// Load the class demo.getInstance () when executing a static method; } static Demo getInstance(){ return demo; } private Demo() {system.out.println (" j = "+ j + ", I =" + I + "); Println (" before finnal initialization: j2 = "+ j2 + ", after finnal: i2 =" + i2 + "); }} Result: j = 0 before non-FINNAL initialization; I = 1 after non-FinNAL initialization; J2 = 2 before FinNAL initialization; i2 = 1 after FinNAL initializationCopy the code

Class instantiation (use one)

  • Allocate memory for new objects
  • Assign default values to instance variables
  • Assign the correct initial value to the instance variable
  • The Java compiler generates at least one instance initialization method for every class it compiles. In Java class files, the instance initialization method is called “”. Constructor for each class in the source code. Java compilers all produce a “” method.

Three types of LOADers for the JVM

The name of the Default loading path
Root classloader (bootstrap classloader) <JAVA_HOME>\lib (rt.jar)
Extension classloader (ext classloader) <JAVA_HOME>\lib\ext (path specified by the java.ext.dir system variable)
App ClassLoader Project $CLASSPATH

The classloader gets a binary stream of bytes describing a class by its fully qualified name, for example (com.libra. One.test.java)

In addition to the above three types of loaders, there is also a custom class loader in the JVM

The BootstarpClassLoader (root class loader) is not written in Java code. The other classloaders are written in Java code and all inherit from the abstract class java.lang.classloader. But these classes are all interdependent. The default three classes of loader dependencies are as follows:

Graph LR application class loader - app - > | | father extension class loader - ext extension class loader - ext - > | | father with class loader - the bootstrap

Custom class loader constructor

// The default parent class loader is the application class loader public Classloader_Demo(String classLoaderName) {super(); This. classLoaderName = classLoaderName; } // Pass a parent of type ClassLoader as the parent of the custom ClassLoader. public Classloader_Demo(ClassLoader parent, String classLoaderName) { super(parent); ClassLoaderName = classLoaderName; this. ClassLoaderName = classLoaderName; }Copy the code

Class loader parent delegate mechanism

The working process of the parental delegation model is:

  1. The classloader receives a classload request
  2. Delegate the request to the parent class loader until the request is passed to the top-level class loader (bootstrap).
  3. The parent loader reported that it could not complete the request
  4. The child loader tries to load itself.

Flow chart:

Graph LR class loading request -- -- > parent class loader Parent class loader - > C {if there is a parent class loader} C - > | true | the parent class loader C - > | FLASE | D {attempts to load} D - > | true | loaded D - > | FLASE | Transfer to child loader --> D{try to load}

demo:

Put the com.libra. Demo.Demo class file into C:\Users\Administrator\Desktop\

Public class Demo3 {public static void main(String[] args) throws Exception {// Create a custom classLoader No parent class loader is specified (default: AppClassLoader) Classloader_Demo loader1 = new Classloader_Demo("loader1"); / / path exists in com. Libra. Demo. Demo. Class files loader1. SetPath (" C: \ \ Users \ \ Administrator \ \ Desktop \ \ "); Class clazz = loader1.loadClass("com.libra.demo.Demo"); Println (" +clazz.getClassLoader()); }} return: clazz classLoader: sun.misc.Launcher$AppClassLoader@18b4aac2Copy the code

Delete com under the project classpath. Libra. Demo. Demo. Class files (i.e. let AppClassLoader load, failure load power returned to custom this)

Public class Demo3 {public static void main(String[] args) throws Exception {// Create a custom classLoader No parent class loader is specified (default: AppClassLoader) Classloader_Demo loader1 = new Classloader_Demo("loader1"); / / path exists in com. Libra. Demo. Demo. Class files loader1. SetPath (" C: \ \ Users \ \ Administrator \ \ Desktop \ \ "); Class clazz = loader1.loadClass("com.libra.demo.Demo"); Println (" +clazz.getClassLoader()); }} return: you're using the name is: the custom of loader1 loader loads clazz this category for: com. Libra. Demo. F612 Classloader_Demo @ 7382Copy the code

Benefits of the parent delegate model for class loaders:

  • Ensures Java core library type safety. Such as: All Java applications reference the java.lang.object class, which means that at runtime the java.lang.object class is loaded into the Java virtual machine. If this loading is done by the Java application using its own class loader, It is likely that there will be multiple versions of the Java.lang. object class in the JVM, and that these classes will be incompatible and not visible to each other. (It’s the namespace that comes into play.)
  • With the help of the parent delegation mechanism, the loading of Java core library classes is agreed by the class loader, which ensures that the Java core libraries used by Java applications are compatible with each other, ensuring that the classes provided by the Java core libraries will not be replaced by custom classes.
  • Different class loaders can create additional namespaces for classes with the same name (binayname). Classes with the same name can coexist in the Java virtual machine and only need to be loaded by different class loaders. Classes loaded by different class loaders are incompatible, which means that they are created inside the Java Virtual machine
  • Isolated Java class Spaces are used in multiple frameworks

Code to implement the parent delegate mechanism

  • If not, the parent loader’s loadClass() force method is called. If the parent loader is empty, the startup class loader is used as the parent loader by default. If the parent class fails to load, throw a ClassNotFoundException and call your own findClass() method to load it. = =
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; }}Copy the code

Break the parental delegation mechanism

  • Current ClassLoader: Each class uses its own class loader to load other classes. If class X refers to classY, then ClassX’s classloader will load classY if classY is not loaded
  • Context ClassLoader: Thread context classloaders are referenced starting with JDk1.2. GetContextClassLoader () and setContextClassLoader () in class Thread are used to get and set context classloaders, respectively. If not set by setContextClassLoader, the thread inherits its parent thread’s context loader. The context loader of the initial thread at Java application runtime is the system class loader, which is the application class loader by default if it is not set globally in the application. Code that runs in a thread can load resources through the class loader.
  • The importance of threaded class loaders: This SPI (Service Provider Interface) father can use the current thread (thead. GetContextClassLoader) make this loading class, This changes the situation where the parent classloader cannot use a child classloader or any other classloader that does not have a direct parent-child relationship to load a class, which changes the parent delegate mechanism.
  • The thread-context ClassLoader is the Current ClassLoader for the Current thread

Set the thread class loader DMOE:

Public class Demo3 {public static void main(String[] args) {system.out.println (); "+Thread.currentThread().getContextClassLoader()); System. The out. Println (" loading Thread class loader: "+ Thread. Class. GetClassLoader ()); System.out.println("----------------------------------"); Classloader_Demo classLoader = new Classloader_Demo("loader1"); Thread.currentThread().setContextClassLoader(classLoader); Thread thread = new Thread(); System. The out. Println (" new thread thread context loader (inherit the parent thread) : "+ thread. GetContextClassLoader ()); thread.setContextClassLoader(ClassLoader.getSystemClassLoader()); System. The out. Println (" new thread thread context loader: "+ thread. GetContextClassLoader ()); } } return : The context loader for the current thread: sun.misc.Launcher$AppClassLoader@18b4aac2 Null -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- new thread thread context loader (inherit the parent thread) : Com.libra.edu cation. Classloader_Demo @ 61064425 new thread thread context loader: sun. Misc. The Launcher $AppClassLoader @ b4aac2 18Copy the code
  • General pattern of class loaders up and down threads (acquisition-use-restore)
ClassLoader ClassLoader = thread.currentThread ().getContextClassLoader() try{// Set a new ClassLoader Thread.currentThread().setContestClassLoader(targrtTocl); myMethod(); }finally{// restore classLoader thread.currentthread ().setcontextclassloader (classLoader); }Copy the code
  • myMethod() The call thread.currentthread ().getcontestclassloader () gets the currentThread’s classloader to do something. If A class is loaded by classloader A, then the class’s dependent classes are also loaded by the same classloader (if the class’s dependent classes are not already loaded) When a high-level class provides a unified interface for low-level implementation and loads (or instantiates) low-level classes at the same time, a thread-context ClassLoader must be used to help the high-level ClassLoader find and load the class

How to obtain a ClassLoader

  • GetClassLoader () : clazz.getClassLoader();
  • GetContextClassLoader: Tread.CurrentThread ().getContextClassLoader;
  • This acquisition system: this. GetSystemClassLoader ();
  • Get the caller’s ClassLoaderL DriverManager. GetCallerClassLoader ();

The namespace of the class loader

Comparing two classes to be “equal” only makes sense if the two classes are loaded by the same Class loader. Otherwise, even if the two classes are from the same Class file and loaded by the same virtual machine, == As long as they are loaded by different Class loaders, the two classes must be different ==.

The namespace

  • Classes loaded by the child loader can access classes loaded by the parent loader
  • The class loaded by the parent cannot access the class loaded by the child loader

Namespace relationships for different class loaders:

  • Classes in the same namespace are visible to each other.

  • The namespace of the child loader contains the namespace of all the parent loaders. So classes loaded by the child loader can see classes loaded by the parent loader.

  • For example, the class of the system class loader can see the class loaded by the class loader

  • Classes loaded by the parent cannot see classes loaded by the child (except context loaders)

  • If there is no direct or indirect parent-child relationship between two loaders, the classes they load are not visible to each other (except for context loaders)

  • A DEMO explaining the above points:

Delete com under the project classpath. Libra. Demo. Demo. Class files (i.e. let AppClassLoader load, failure load power returned to custom this)

Public class Demo2 {public static void main(String[] args) throws Exception {// Create two loading paths Com. Libra. Demo. Demo. Class files in two path / / but you have to under the project classpath com. Libra. Demo. Demo. The class file deletion Classloader_Demo (prevent APP class loader loads) loader1 = new Classloader_Demo("loader1"); loader1.setPath("C:\\Users\\Administrator\\Desktop\\"); Classloader_Demo loader2 = new Classloader_Demo("loader2"); loader2.setPath("C:\\Users\\Administrator\\Desktop\\log\\"); Clazz = loader1.loadClass("com.libra. Demo.Demo"); Class clazz2 = loader2.loadClass("com.libra.demo.Demo"); System.out.println(clazz.equals(clazz2))); }} return: you are using a custom loader named loader1 you are using a custom loader named loader2 falseCopy the code

Custom classLoade

public class Classloader_Demo extends ClassLoader { private String classLoaderName; // Loader name private String path; Private final Static String fileExtension = ".class"; Public Classloader_Demo(String classLoaderName) {super(); This. classLoaderName = classLoaderName; } public Classloader_Demo(ClassLoader parent, String classLoaderName) { super(parent); ClassLoaderName = classLoaderName; this. ClassLoaderName = classLoaderName; } @override // find the file to load according to the binary name. Throws ClassNotFoundException {system.out.println (" You are using the name as: "+this.classLoaderName+" custom loader "); byte[] data = loaderClassData(name); return this.defineClass(name, data, 0, data.length); } // Read file into Data through IO (into bytecode) private byte[] loaderClassData(String name) {InputStream IO = null; byte[] data = null; ByteArrayOutputStream baos = null; name = name.replace(".","\\"); String s = this.path + name + this.fileExtension; try { io = new FileInputStream(new File(this.path+name+this.fileExtension)); baos = new ByteArrayOutputStream(); int ch = 0; while (-1 ! = (ch = io.read())) { baos.write(ch); } data = baos.toByteArray(); } catch (Exception e) { e.printStackTrace(); } finally { try { io.close(); baos.close(); } catch (IOException e) { e.printStackTrace(); } } return data; } public void setPath(String path) { this.path = path; }}Copy the code