If the core library API is more like making mathematical formulas, then the knowledge of the Java Virtual machine is more like deriving formulas

Class life cycle

  • Loading
    • Four types of loaders:
    • Contents of the JAVA_HOME directory
    • Parents to appoint
  • Linking
    • Validation phase
    • Preparation stage
    • Parsing stage
  • Initialize the
    • Seven triggers for class initialization:
  • uninstall

JVM

Every introduction to the Java language will mention that Java is cross-platform, “explained once, run everywhere”, thanks to the JVM (Java Virtual Machine).

However, if the JVM is tied to the Java language only, the understanding is too narrow, and the Java virtual machine has evolved away from the Java language, forming a relatively independent, high-performance execution scheme.

image

In addition to the languages mentioned above, Scala and the popular Kotlin all run on the JVM.

JVM memory structure specification

I’ll take a quick look at the JVM memory structure and then go into details about how this area is stored.

Class life cycle

The entire life cycle of a class from when it is loaded into virtual memory to when it is unloaded includes:

The entire life cycle of a class from load to unload

Tip:

  1. The load and connect phases are sometimes interleaved and do not need to wait until full load is complete.
  2. The parsing phase can sometimes be done after initialization. The Jvm simply specifies that if some bytecodes use symbolic references, they need to be resolved before they can be executed.
  3. But the total start time and finish time of these processes are in the same order as above.
  4. The “loading phase” here is different from what we often call “class loading,” which is the sum of the three parts in the dotted box.

Loading

Loading is the process of finding byte streams and creating classes based on them. Is a phase of the class loading process. The virtual machine needs to do three things in this process:

  • Get the binary byte stream of a class by its fully qualified name;
  • Convert the static storage structure represented by this byte stream to the runtime data structure of the method area;
  • Generate a java.lang.Class object representing the Class in memory as an access point to the Class’s various data in the method area.
Class loading

From the perspective of virtual machines, there are only two different class loaders: one is the Bootstrap ClassLoader, which is implemented in C++ and is part of the virtual machine. The other is all the other classloaders, which are implemented in the Java language, independent of the JVM, and all inherit from the abstract java.lang.classloader.

Four types of loaders:

  1. Bootstrap the class loader

The launcher class loader is responsible for loading the most basic and important classes. Is responsible for loading the class libraries under JAVA_HOME/lib into memory (such as rt.jar). Since bootstrap classloaders involve the details of the virtual machine’s local implementation, the developer cannot get a reference to the bootstrap classloader directly, so direct operations are not allowed.

Note: the launcher class loader is implemented by C++ and has no corresponding Java object, so it can only be referred to as null in Java. Except for the launcher ClassLoader, all classloaders are subclasses of java.lang.ClassLoader and therefore have corresponding Java objects. These classloaders need to be loaded into the Java virtual machine by another classloader, such as the launcher classloader, before they can perform class loading.

  1. The standard Extension class loader

It is responsible for loading relatively minor but generic classes, loading into memory libraries in JAVA_HOME/jre/lib/ext or at the location specified by the system variable java.ext.dirs.

  1. The Application class loader

It is responsible for loading the libraries specified in the system CLASSPATH into memory. Since this ClassLoader is the return value of the getSystemClassLoader() method in ClassLoader, it is commonly referred to as the System loader

  1. Custom class loaders

In addition to the class loaders provided by the Java core class library, we can also add custom class loaders to implement special loading methods. For example, a class file can be encrypted and decrypted by a custom class loader at load time.

Contents of the JAVA_HOME directory

The reason I wrote this is because there are very few people in development who open this folder and look at it.

The JAVA_HOME/bin directory contains many commands
JAVA_HOME/lib directory
JAVA_HOME/jre/lib directory
JAVA_HOME/jre/lib/ext directory

Parents to appoint

Parent mandates workflow

The parent delegate mechanism workflow:

  1. The current ClassLoader first checks whether the class has been loaded. If it has been loaded, it returns the previously loaded class.

Each class loader has its own load cache. When a class is loaded, it is put into the cache and then returned the next time it is loaded.

  1. When the current classLoader does not find the loaded class in the cache, it delegates the load to the parent classLoader. The parent classLoader adopts the same strategy, first looks at its own cache, and then delegates the load to the parent class until bootstrp classLoader.

  2. When none of the parent class loaders is loaded, it is loaded by the current class loader and placed in its own cache so that it can be returned the next time there is a load request.

Why do we need parental mandate security mechanisms?

  1. Intuitive understanding

Imagine a hacker customizing a java.lang.String class that has the same functionality as the system’s String class, with a slight change in one function. This function is often used if some “virus code” is inserted into this function. And added to the JVM via a custom class loader. Finished, the program cool cool, this is more intuitive understanding.

  1. The real reason

To fully understand this problem, we need to introduce the concept of class namespaces.

A class needs to be identified by the fully qualified name of the class (the full path of the class) and the ClassLoader that loads the class. That is, even if two classes have the same fully qualified name, they are different classes in the JVM because different classloaders load this class.

Such as said above, we provide the JDK’s this life of the libraries, such as string, hashmap, linkedlist and so on, these classes by bootstrp class loader to load, no matter you have how many class loader in the program, all of these classes are then can be Shared, This avoids confusion when different class loaders load different classes with the same name.

Summary:

  1. Check order: bottom up
  2. Loading sequence: top down

Linking

Validation phase

When a class is loaded, it must be verified that the class is legal, such as whether the class conforms to the format of the bytecode, whether the variables and methods are duplicate, whether the data type is valid, whether the inheritance and implementation are standard, and so on.

The Java compiler generates class files that must meet the constraints of the Java virtual machine, but in order to prevent “de-bytecode injection”.

In the verification phase, the following four stages will be roughly completed:

  • File format verification (Mainly to verify whether the Class file format specification is met, and can be processed by the current version of the VM.)

Verification based on binary byte stream, only after passing the verification of this stage, byte stream will enter the method area of memory for storage, so the subsequent verification stage is based on the storage structure of the method area, will not directly operate the byte stream.

  • Metadata validation (semantic analysis of the information described by bytecode to ensure that the information described conforms to the Requirements of the Java language specification)

For example, verify that the class has a parent (except for java.lang.Object, which is the parent of all classes), and if the class is not an abstract class that implements all the methods required by the parent or interface, etc.

  • Bytecode verification
  • Symbolic reference validation (occurs when the virtual machine converts a symbolic reference to a direct reference, which occurs during the connection’s third phase of parsing)

For example, verify that a class can be found for a fully qualified name described by a string in a symbolic reference.

Preparation stage

It allocates memory for static variables of the class and sets them to the JVM’s default initial value, rather than what we set. This will be done during a later phase of initialization. For non-static variables, no memory will be allocated.

The JVM’s default initial value looks like this:

The default value for basic types (int, long, short, char, byte, Boolean, float, double) is 0. There are only two types of Boolean, true and false, which correspond to the JVM value 1,0 respectively.

The default value for a reference type (object, array) is NULL.

Construct other data structures related to the class hierarchy, such as method tables used to implement dynamic binding of virtual methods.

Until the class file is loaded into the Java virtual machine, the class cannot know the addresses of other classes, their methods, and fields, or even its own methods and fields. Therefore, the Java compiler generates a symbolic reference every time it needs to reference these members. In the run phase, the symbolic reference is usually unambiguously located to the specific target (because the symbolic reference is verified in the validation phase).

Exception: public static final int value=123

Parsing stage

The above mentioned “in the run phase, the symbol reference can be unambiguously located to the specific target”, is the symbol resolution in the parsing phase.

The purpose of this phase is to parse symbolic reference transformations from the constant pool into actual references. During the parsing phase, the JVM converts all class or interface names, field names, and method names into specific memory addresses so that classes that use other classes or interfaces can find and load other classes/interfaces.

If a symbolic reference points to a class that is not loaded, or to a field or method of the class that is not loaded, parsing will trigger the loading of the class (but not necessarily the linking and initialization of the class)

Initialize the

In Java code, if we want to initialize a static field, we can assign it directly at declaration time, or we can assign it in a static code block. With the exception of final static modified constants, direct assignment operations and code in all static code blocks are placed in the same method by the Java compiler and named < clinit >.

The final step in class loading is initialization, the purpose of which is to assign values to fields marked as constant values and the process of executing the < Clinit > method. The Java virtual machine locks to ensure that the class’s < clinit > methods are executed only once.

Seven triggers for class initialization:

  1. When the virtual machine starts, initialize the main class specified by the user (main function).

  2. Initialize the target class of the new instruction when it encounters a new instruction for creating an instance of the target class.

  3. When an instruction that calls a static method is encountered, initialize the class of the static method;

  4. Initialization of a subclass triggers initialization of its parent class;

  5. If an interface defines the default method, the initialization of the class that implements the interface directly or indirectly triggers the initialization of the interface.

  6. Initialize a class when a reflection call is made to the class using the reflection API;

  7. The first time you call a MethodHandle instance, you initialize the class to which the method points.

Singleton lazy loading in the design pattern takes full advantage of this feature.

uninstall

So many classes, when and who to uninstall? About whom to uninstall, the following conditions are met:

  1. All instances of the class have been reclaimed, that is, there are no instances of the class in the Java heap;

  2. The ClassLoader that loaded the class has been reclaimed;

  3. The java.lang.Class object corresponding to this Class is not referenced anywhere, and the methods of this Class cannot be accessed through reflection anywhere.

As for when to uninstall, when the above conditions are met, garbage collection time back to the method area empty the class information to uninstall, hero late, the life of this class is also come to an end.