Class loading

Java goes from coding to execution

Javac compiles the Java ClassLoader to load the Class bytecode interpreter and the JIT just-in-time compiler to execute the engine

The JVM includes a ClassLoader bytecode interpreter, JIT just-in-time compiler, and execution engine, so anything that compiles to Class files and complies with JVM standards can be executed by the JVM, such as Kotlin, Scala, Spark, etcCopy the code

What is the Class

The Class file is a heap of bytecode binary byte streams that can be viewed in hexadecimal. The Class file contains the following contents

Uniform identifiers, file version numbers, class names, constant pools, superclasses, number of implemented interfaces, list of implemented interfaces, access modifiers (such as final, public, private, etc..) , member variables, etc., can BE viewed through javap -v class files or installed plug-ins such as JClass Lib, CA FE BA BE and 00 00 00 34 file version number hexadecimalCopy the code

If you are interested in the Class description in the official documentation, read the official documentation for yourself

A class file consists of a single ClassFile structure:
ClassFile {
u4 magic;
u2 minor_version;
u2 major_version;
u2 constant_pool_count;
cp_info constant_pool[constant_pool_count-1];
u2 access_flags;
u2 this_class;
u2 super_class;
u2 interfaces_count;
u2 interfaces[interfaces_count];
u2 fields_count;
field_info fields[fields_count];
u2 methods_count;
method_info methods[methods_count];
u2 attributes_count;
attribute_info attributes[attributes_count];
}
The items in the ClassFile structure are as follows:
Copy the code

Class loading process

There are three major stages

  1. Load (by load I mean load the Class file)
  2. Linking (link)
  3. Initialize the Class

Loading Linking Initializing

Loading

Loading is the process of Loading the corresponding Class file from the storage area into memory. FindClass in the ClassLoader finds the corresponding Class and loads it into memory

Linking

The Linking stage is divided into three substages

verification

Verification verifies the validity of a Class file to verify whether the corresponding Class file is a normal Class file

preparation

Preparation is a preparation phase that assigns default values to some of the fields corresponding to static variables in the Class file, such as a static int a = 8, where a is assigned a value of 0

resolution

The resolution resolution Class file converts symbolic references in the Class file to direct references. This section is actually the virtual method table for dynamic method calls and data loading in the method area described in the previous article.

initialization

The Class file generates a

method when the Class file has static variables or code blocks. The clinit method is used to initialize the Class file. Static int a = 8 static int a = 8

ClassLoader ClassLoader

There are two general categories

One implements the BootstarpClassLoader for the JVM virtual machine

One class inherits ClassLoader in Java to implement ExtClassLoader AppClassLoader custom ClassLoader

Bootstrap:

Jar, rt.jar, charset.jar and other core C/C++ implementations

The null return from getClassloader is loaded by Bootstrap.

Bootstrap does not inherit the ClassLoader implementation. Bootstrap is the lowest level ClassLoader

Extension: The ExtClassLoader loads the Extension JAR package or the path specified by -djava.ext.dirs

Application: AppClassloader loads the classpath content -djava.class.path

Custom loader: Inherits the Classloader implementation

What is this

ClassLoader is a Class loader that loads binary data or other data into memory and then generates a pointer to the corresponding memory address to complete the reading of the Class file

ClassLoader loading process

Parents delegate

When a Class file needs to be used, the loader will first check whether it is loaded according to the hierarchy above

The custom loader checks to see if it is loaded, and if it is not, it delegates the check to its parent loader (not the inheritance relationship, but the hierarchy), which is the AppClassLoader

If the AppClassloader has not been loaded, go up and check the ExtClassLoader. If the ExtClassLoader has not been loaded, delegate to the Bootstrap

If Bootstrap does not find the corresponding Class, it will throw a ClassNotFoundException and delegate

Delegate to the ExtClassLoader and the ExtClassLoader will also load the corresponding class and throw a ClassNotFoundException if it’s not loaded and delegate to the AppClassLoader

If the AppClassLoader can’t find it, hand it over to the custom loader and of course if there’s no custom loader on the AppClassLoader this layer is over if there’s a custom loader on the AppClassLoader it’s loaded and if there’s no Class on the AppClassLoader ClassNotFoundException is thrown

Each class loaded by a Classloader is cached by itself

You can view the source code corresponding to Sun.misc.Launcher yourself

Why parent delegate?

  1. Security issues

    It’s just for security if you don’t design it that way then you define any Class and you load it yourself, like using a third-party library where you write a java.lang.String Class, So it’s going to be loaded into memory by a third party and so when we use a String that’s going to be modified by a third party like the hook that we’re reporting the data to and so forth then the data that we’re using the String is going to be taken away by that third party

  2. The same class may be loaded multiple times, and the previous layer may have already been loaded

Can I break the parental delegation pattern?

Parental delegation models are not mandatory models

  1. SPI callers and interface definers are likely to be in Java’s core class library, while the implementation classes are handed over to the developer. However, the implementation classes are not loaded by the starting class loader, and due to the visibility principle of parental delegation, SPI callers cannot get the implementation classes. SPI Serviceloader bypasses this limitation by getting a classloader that can load implementation classes in a thread context, typically an AppClassloader. The logic breaks the parent delegate principle. Such as the JDBC DriverManager

  2. Hot loading overrides loadClass instead of findClass and checks each time from an address and reloads if there is a new one such as the hot deployment mechanism in Tomcat

The custom this

When do I need to load a class myself?

Hot deployment dynamic remote loading lib Spring dynamic proxy load resource encryption Class, etc. (SDK uses encryption through AppId to the server to obtain the secret key decryption can be used)... , etc.Copy the code

How does Class load a Class?

  1. If the Class is not loaded, call Parent to load the Class and throw a ClassNotFoundException to indicate that the Class was not found. Find the Class using findClass. So if you need a custom loader, you need to override the findClass method

    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

The template mode used by ClassLoader defines the basic implementation logic and requires subclasses to perfect the corresponding lookup logic. AQS also uses template mode and requires its own implementation of the specific successful lock logic and lock release logic

FindClass can load a file as a byte array and then use defineClass to wrap binary data as a pointer to a Class Class. The last implementation to load is a virtual machine implementation implemented by C++ The lazy loading mode of the corresponding class is loaded only on demand

When to load

The JVM doesn’t specify when to load, the JVM itself uses lazy loading but it specifies when to initialize, right

1. New getstatic putstatic invokestatic 2. The parent class is initialized first when the child class is initialized. 4. The main class is initialized when the VM starts. Dynamic languages support methods that must be initialized when the result of a MethodHandle resolution is a getstatic putstatic Invokestatic methodCopy the code

How does the JVM execute a Class file

Here I have sketched some of the modules that the JVM as a whole contains

The JVM runtime data area has been covered in previous articles, but here we’ll focus on the execution engine

Cross-platform language

Why is Java a cross-platform language?

The so-called cross-platform language actually depends on the JVM virtual machine, which can be understood as a Class file execution virtual environment. The JVM itself defines a set of JVM instructions, and translates or compiles the corresponding bytecode files into the operating system of the next layer of the VIRTUAL machine by parsing the Class file. The Class file has nothing to do with the operating system, but the virtual machine implements a set of instructions to translate the bytecode file into the corresponding operating system

JVM is a virtual machine, Java is a high-level language that is eventually compiled into a Class bytecode file, like other things like Scala, Kotlin,Groovy and so on that can be compiled into Class bytecode and run on the JVM, Anything that complies with the Class bytecode specification can run on the JVM

JVM Execution process

Java is often referred to as a semi-compiled and semi-interpreted language, mainly because Java has two directions of execution: interpreted execution and JIT-compiled machine-code instruction execution

Of course there’s a lot more to JIT JIT compilation and I’ve omitted some of it here and intermediate code generation register allocators and so on