An overview of the
The entire life cycle of a class from the moment it is loaded into virtual machine memory to the moment it is unloaded from memory includes: loading
Loading, Verification, Preparation, Resolution, initialization
1. There are seven Initialization, Using and Unloading stages. Verify, prepare and parse
The three parts are collectively known as Linking.
During the initialization phase, the VIRTUAL machine specification specifies that there are only five cases in which classes must be “initialized” immediately
Loading, validation, and preparation of course need to start before that:
1) When new, getstatic, putstatic, or Invokestatic are encountered, if the class does not proceed
If the initialization is over, the initialization needs to be triggered first. The most common Java code scenario that generates these four instructions is: use
The new keyword instantiates an object, reads, or sets a static field of a class (modified by final and compiled)
To put results into static fields of the constant pool), and to call static methods of a class.
2) When a java.lang.reflect class is called using a java.lang.reflect method, if the class has not been initialized,
You need to trigger its initialization first.
3) When initializing a class, if the parent class has not been initialized, the parent class needs to be triggered first
Initialization of.
4) When the virtual machine starts, the user needs to specify a main class (the one containing the main () method) to execute.
The virtual machine initializes the main class first.
5) when using JDK 1.7 dynamic language support, if a Java lang. Invoke. Most MethodHandle instance
REF_getStatic, REF_putStatic, REF_invokeStatic, and REF_invokeStatic
If the class corresponding to the method handle has not been initialized, it needs to be initialized first.
Note:
For a static field, only the class that directly defines the field is initialized, so the parent class is referred to by its subclass
A static field that triggers initialization of the parent class but not of the subclass.
The constant HELLOWORLD, which is optimized for constant propagation at compile time, has been set to “hello”
World is stored in the constant pool of the NotInitialization class
References to constclass. HELLOWORLD are actually converted to references to the NotInitialization class’s own constant pool
Use.
That is, there are no ConstClass symbols referenced in the NotInitialization Class file
These two classes have no relationship after being translated into Class.
Loading stage
The VM needs to do the following three things:
1) Get the binary byte stream that defines a class by its fully qualified name.
2) Convert the static storage structure represented by this byte stream to the runtime data structure of the method area.
3) Generate a java.lang.Class object in memory that represents the Class and holds the various data of the Class as a method area
Access to.
validation
Is the first step in the join phase, which ensures that the information contained in the byte stream of the Class file matches
Requirements of the current VM and does not compromise VM security. But on the whole, the validation phase will be roughly
Complete the following four stages of verification: file format verification, metadata verification, bytecode verification, symbol reference verification
Certificate.
Preparation stage
Is the stage where you formally allocate memory for class variables and set their initial values. The memory used by these variables will be in the method
Area to allocate. There are two confusing concepts that need to be emphasized at this stage
Memory allocation includes only class variables (static modified variables), not instance variables, which will be allocated in the
Object instantiation is allocated in the Java heap along with the object. Second, the initial values mentioned here are “normally”
Is the zero value of the data type, assuming a class variable is defined as:
Public static int value=123;
The initial value of the variable value after the preparation phase is 0 instead of 123, because nothing has been executed yet
The putStatic instruction, which assigns a value of 123 to the putStatic instruction, is stored in the class constructor <
Clinit > () method, so assigning value to 123 will only take place during initialization. Table 7-1
Lists zero values for all basic data types in Java.
Public static final int value=123;
At compile time Javac will generate a ConstantValue attribute for the value, which the virtual machine will base on during the preparation phase
ConstantValue sets value to 123.
Parsing stage
Is the process by which the virtual machine replaces symbolic references in the constant pool with direct references
Class initialization phase
Is the last step in the class loading process. In the previous class loading process, the user application can pass except during the loading phase
Outside of the custom class loader, the rest of the action is completely led and controlled by the virtual machine. When you get to the initialization phase, it’s really
Start executing the Java program code defined in the class. In the preparation phase, the variable has been assigned the initial value required by the system.
In the initialization phase, class variables and other resources are initialized according to a programmer’s subjective plan made by the program, or
This can be expressed another way: the initialization phase is the process of executing the class constructor < clinit > () method. The <
The Clinit > () method is automatically collected by the compiler for assignment actions and static statement blocks (static{}) for all class variables in a class.
Block. The order in which the compiler collects the statements is determined by the order in which they appear in the source file.
The < clinit > () method is not required for a class or interface, and if a class does not have a static block, neither does it
If there are assignments to variables, the compiler may not generate the < clinit > () method for this class.
The virtual machine ensures that a class’s < clinit > () methods are locked and synchronized correctly in a multithreaded environment, if multiple
If a thread initializes a class at the same time, only one thread will execute the class’s < clinit > () method, and the rest
Threads need to block and wait until the active thread completes executing the < clinit > () method. If in a class < clinit
Long operations in the > () method can cause multiple processes to block.
Class loader
How to customize class loader, look at the code
Class loader for the system
For any class, its presence in the Java Virtual machine needs to be established both by the classloader that loads it and by the class itself
Each class loader has a separate class namespace. This sentence can be expressed more colloquially
Some: Comparing two classes for “equality” is only useful if they are loaded by the same classloader
Otherwise, even if the two classes come from the same Class file and are loaded by the same virtual machine, just load them
The two classes must not be equal.
The equals () method, isAssignableFrom, represents the Class objects of the Class
() method, isInstance () method, and object ownership using the instanceof keyword
Department decision and so on.
When customizing a ClassLoader subclass, there are two common approaches. One is to override the loadClass
The alternative is to override the findClass method. In fact, the two methods are essentially the same, after all, loadClass will also
Call findClass, but logically it is best not to modify the internal logic of loadClass directly. I suggest that the
The idea is to override the loading methods of custom classes only in findClass.
The loadClass method is where the parent delegate model logic is implemented, and tampering with this method will cause the model to be broken
Bad, easy to cause problems. Therefore, it is best to make small changes within the framework of the parental delegation model without breaking the original
There are stable structures. It also avoids the repetition of having to write parent delegates when overwriting the loadClass method itself
Code, in terms of the reusability of the code, it is always better not to modify this method directly.
Parental delegation model
From the Perspective of the Java virtual machine, there are only two different class loaders: one is to start the class loader
(Bootstrap ClassLoader), which is implemented in C++ language and is part of the virtual machine itself;
The other is all the other class loaders, which are implemented in the Java language and are independent of the virtual machine
And all inherit from the abstract java.lang.ClassLoader class.
Bootstrap ClassLoader: this ClassLoader is responsible for storing it in < JAVA_HOME > \lib
Directory, or the path specified by the -xbootCLASSPath parameter, and is recognized by the virtual machine
File name recognition, such as rt.jar, and libraries with incorrect names will not be loaded even if placed in the lib directory
Vm memory. The startup class loader cannot be referenced directly by Java programs. The user is writing a custom class loader
If you need to delegate the load request to the bootstrap classloader, use NULL instead.
Extension ClassLoader: This loader is created by Extension ClassLoader
Sun.misc.Launcher$ExtClassLoader, which loads the < JAVA_HOME > \lib\ext directory
, or all libraries in the path specified by the java.ext.dirs system variable, developers can use the extension directly
Class loader.
Application ClassLoader: This ClassLoader is called sun.misc.Launcher
$App – this implementation. Since this ClassLoader is getSystemClassLoader in ClassLoader
The return value of the () method, so it is also commonly called the system classloader. It is responsible for loading the user classpath
(ClassPath). Developers can use this class loader directly if the application does not have one
Class loaders have been customized, and this is usually the default class loader in the program.
All of our applications are loaded by these three types of loaders in conjunction with each other and, if necessary, by adding custom loaders
Class loader that has been defined.
The parent delegate model requires that all class loaders have their own parent class loaders, except for the top-level start class loaders
Device. The parent-child relationship between classloaders is not typically inherited, but both
Use Composition relationships to duplicate parent loader code.
One of the obvious benefits of using the parent-delegate model to organize the relationships between class loaders is that Java classes follow
Its classloaders come together with a hierarchy of priorities. For example, the java.lang.Object class, which is stored in
In rt.jar, any class loader that loads this class ends up delegating to the starting class at the top of the model
The loader loads, so the Object class is the same class in each classloader environment of the program. On the contrary, if
Instead of using the parent delegate model, each class loader loads it by itself, if the user writes a code called
Java.lang.Object classes, and put them in the ClassPath of the program, and several different ones will appear in the system
The Object class, the most basic behavior of the Java type system, would not be guaranteed, and the application would become chaotic.
Tomcat class loading mechanism
Tomcat itself is a Java project, so it also needs to be loaded by the JDK’s classloading mechanism and therefore must exist
Boot class loaders, extension class loaders, and application (system) class loaders.
The Common ClassLoader acts as the parent of Catalina ClassLoader and Shared ClassLoader
Shared classloaders may also have multiple Children classloaders, one WebApp ClassLoader
A WebApp ClassLoader actually corresponds to a Web application, and that Web application might have Jsp pages
These Jsp pages will eventually be loaded as class classes, so a Jsp classloader is also required.
Catalina ClassLoader, Shared ClassLoader, and Common at the code level
The entity classes corresponding to ClassLoader are actually URLClassLoader or SecureClassLoader
We simply divide these three classloaders logically based on the difference in content being loaded and the parent-child order of loading;
Both WebApp ClassLoader and JasperLoader have corresponding ClassLoader classes.
When Tomcat is started, several types of loaders are created:
1 Bootstrap The Bootstrap class loader loads the classes required to start the JVM, as well as the standard extension classes (located in jre/lib/ext)
Below)
2 System The System class loader loads classes that tomcat starts, such as bootstrap.jar, usually in Catalina.bat
Or specified in catalina.sh. It is in CATALINA_HOME/bin.
The Common class loader loads some Common classes that Tomcat uses and applies, located in
CATALINA_HOME/lib, for example, servlet-api.jar
4 WebApp Class loader After each application is deployed, a unique class loader is created. Class loader
Classes in jar files in WEB-INF/lib and classes in Web-INF /classes are loaded.
Method call details
parsing
The call target must be determined when the program code is written and the compiler compiles. Calls to such methods are called solutions
Analysis.
In the Java language, methods that meet the requirement of “compile-time knowable, run-time immutable” mainly include static methods
And private methods, which are directly associated with the type, and private methods, which cannot be accessed externally
The dot determines that none of them can override another version by inheritance or otherwise, so they are all suitable for class loading
Parse.
Static dispatching
See method overloading more often.
“Human” is the Static Type of a variable, or the Apparent Type
Type), followed by “Man” is called the Actual Type of the variable
The difference is that the static type changes only when used, the variable itself is static
The type is not changed, and the final static type is known at compile time; The result of the actual type change is running
The compiler does not know what the actual type of an object is when it compiles the program.
The code defines two variables of the same static type but different actual type, but the virtual machine (or compiler, to be precise)
Overloading is determined by the static type of the parameter rather than the actual type. And static typing is compile-time
Therefore, at compile time, the Javac compiler decides which overloaded version to use based on the static type of the parameter
Ben, so sayHello (Human) was selected as the call target. All rely on static types to locate method implementations
Ben’s dispatch action is called static dispatch. A typical use of static dispatch is method overloading. Static dispatch occurs at the compile level
Segment, so determine that statically dispatched actions are not actually performed by the virtual machine.
Dynamic dispatch
Static types man and woman, both Human variables, are executed when the sayHello () method is called
Different behavior, and the variable man executes different methods in the two calls. The reason for this phenomenon is quite clear
It turns out that the actual types of the two variables are different.
In the implementation, the most common means is to create a virtual method table for the class in the method area. The virtual method table holds each
The actual entry address of the method. If a method is not overridden in a subclass, the address in the subclass’s virtual method list
The entry is identical to the address entry of the same method in the parent class, pointing to the implementation entry of the parent class. If I override this in my subclass
The address in the subclass method table will be replaced by the entry address pointing to the subclass implementation version. In the PPT picture, Son
Overrides all methods from Father, so Son’s method table has no arrows pointing to Father data. but
Neither Son nor Father overrides methods from Object, so all of their method tables inherit from Object
All methods refer to the data type of Object.
Stack – based bytecode interpretation execution engine
The instruction stream the Java compiler outputs, basically, is a stack-based instruction set architecture, with most of the instructions in the instruction stream
Are zero-address instructions that rely on operand stacks to work. with
Register-based instruction sets, the most typical is the x86 two address instruction set, colloquially speaking, is now we
An instruction set architecture directly supported in mainstream PCS that relies on registers for work.
The simplest example is to compute the result of “1+1” using the two instruction sets separately. The stack-based instruction set is this
It looks like:
iconst_1
iconst_1
iadd
istore_0
After the two iconst_1 instructions push the constant 1 onto the stack, the iadd instruction adds the two values at the top of the stack
Istore_0 puts the top of the stack into Slot 0 of the local variable table.
If register-based, the program might look something like this:
Mov eax, 1
The add eax, 1
The MOV instruction sets the value of the EAX register to 1, and the add instruction increments the value by 1. The result is stored in EAX
In the register.
The main advantage of the stack-based instruction set is that it is portable; registers are provided directly by the hardware on which the program depends
Registers are inevitably constrained by hardware. The main disadvantage of stack architecture instruction sets is that execution speed is relatively low
A little slower. The instruction set of all major physical machines is a register architecture which also confirms this point from the side.