1 Overview of the execution engine

  • The execution engine is one of the core components of the Java Virtual Machine
  • The execution engine of a VM is implemented by software, while the execution engine of a physical machine is implemented by the OPERATING system
  • The ability to execute instruction formats that are not directly supported by hardware

Execute the working process of the engine

  • 1. What bytecode instructions does the execution engine need to execute entirely depending on the PC register
  • 2, each time after the execution of an instruction operation, the PC register will update the address of the next instruction to be executed
  • 3. Of course, during the execution of the method, the execution engine may accurately locate the object instance information stored in the Java heap through the object reference stored in the local variable table, and locate the type information of the target object through the metadata pointer in the object header

2 Java code compilation and execution process

Most program code needs to go through the following steps before it can be converted into object code of the physical machine or the instruction set executed by the virtual machine:Java code compilation is done by the Java source compiler, as shown in the following flowchart:

What is an Interpreter and what is a JIT compiler? Interpreter: When the Java virtual machine starts, the bytecode is interpreted line by line according to predefined specifications, and the contents of each bytecode file are “translated” into the local machine instructions of the corresponding platform. The JIT (Just In Time Compiler) Compiler is executed: The virtual machine compiles the source code directly into the machine language that is relevant to the local machine platform

Why is Java a half-compiled, half-interpreted language?In the JDK1.0 era, it was more accurate to define the Java language as “interpreted execution.” More recently, Java also developed compilers that could generate native code directly. JVM execution of Java code now typically involves a combination of interpreted execution and compiled execution

Machine code, instruction, assembly language

3.1 the machine code

  • The various instructions expressed in binary code are called machine instructions. From the beginning, people used it to write programs. It was called machine language
  • Although machine language can be understood and accepted by computers, it is too different from human language to be easily understood and remembered by people, and it is easy to make mistakes in programming
  • As soon as a program written in it is entered into the computer, the CPU reads and runs it directly, so it is the fastest compared to programs written in other languages
  • Machine instructions are closely related to the CPU, so different kinds of cpus have different machine instructions

3.2 instruction

  • Instructions were invented because machine code was a binary sequence of zeros and ones, which was very unreadable
  • Instruction is to simplify the specific sequence of 0 and 1 in machine code into corresponding instruction (generally abbreviated as English, such as MOV, inc, etc.), which is slightly more readable
  • Because different hardware platforms may have different machine codes for performing the same operation, the same instruction (such as MOV) on different hardware platforms may also have different machine codes

Instruction set

  • Different hardware platforms support different instructions. Therefore, the instructions supported by each platform are called the instruction set of the corresponding platform
  • The x86 instruction set corresponds to the x86 platform, and the ARM instruction set corresponds to the ARM platform

3.3 Assembly Language

  • Because the instructions were still too unreadable, assembly language was invented
  • In assembly language, Mnemonics are used to replace the opcodes of machine instructions, and address symbols or labels are used to replace the addresses of instructions or operands
  • In different hardware platforms, assembly language corresponds to different machine language instruction sets, which are converted into machine instructions through the assembly process (because the computer only knows the instruction code, so the program written in assembly language must be translated into machine instruction code, so that the computer can recognize and execute)

3.4 High-level Languages

  • To make programming easier for computer users, various high-level computer languages have emerged. High-level language is closer to human language than machine language or assembly language
  • When a computer executes a program written in a high-level language, it still needs to interpret and compile the program into the machine’s instructions. The program that does this is called an interpreter or compiler

3.4.1 track bytecode

  • Bytecode is a binary code (file) of intermediate state (intermediate code) that is more abstract than machine code and needs to be translated by a translator to become machine code
  • Bytecode is mainly used to implement specific software operation and software environment, and has nothing to do with hardware environment
  • Bytecode is implemented through compilers and virtual machines. The compiler compiles the source code into bytecode, which is translated into instructions that can be executed directly by the virtual machine on a particular platform. A typical use of bytecode is Java Bytecode

3.4.2 C and C++ source program execution process

The compilation process can be divided into two phases: compilation and assembly

  • Compilation process: it is to read the source program (character stream), analyze its morphology and syntax, and convert high-level language instructions into functional equivalent assembly code
  • Assembly process: Actually the process of translating assembly language code into target machine instructions

4 the interpreter

The original intention of the JVM designers was simply toJava programs to achieve cross-platform features, thus avoiding static compilation to directly generate local machine instructions, giving birth to the idea of implementing an interpreter that interprets bytecode execution at run time, line by line

  • The interpreter’s true role is as a runtime “translator”, “translating” the contents of a bytecode file into local machine instructions for the corresponding platform
  • After a bytecode instruction is interpreted, the next bytecode instruction to be interpreted is recorded in the PC register

Throughout the history of Java, there have been two sets of interpreters: the ancient bytecode interpreter and the now-ubiquitous template interpreter. In HotSpot VM, the Interpreter consists mainly of the Interpreter module, which implements the Interpreter’s core functions, and the Code module, which manages the local machine instructions generated by HotSpot VM at runtime

The status quo

  • Because the interpreter is so simple in design and implementation, there are many high-level languages besides the Java language that are also executed based on the interpreter, such as Python, Perl, Ruby, and so on. But today, interpreter-based execution is a byword for inefficiency and is often mocked by SOME C/C+ + programmers
  • To address this problem, the JVM platform supports a technique called just-in-time compilation. The purpose of just-in-time compilation is to avoid the function being interpreted. Instead, the whole function body is compiled into machine code, and only the compiled machine code is executed each time the function is executed. This method can greatly improve the execution efficiency

5 JIT compiler

5.1 Why does the HotSpot VM interpreter coexist with the JIT compiler

  • The first is to compile the source code into a bytecode file and then convert the bytecode file to machine code for execution through the interpreter at run time
  • The second is compilation execution (directly compiled into machine code). Modern virtual machines use just-in-time (JIT) compilation techniques to compile methods into machine code and then execute them to improve execution efficiency

HotSpot VM is one of the representative high performance virtual machines in the market. It uses the == interpreter and just-in-time compiler architecture ==. As the Java Virtual machine runs, the interpreter and the just-in-time compiler can work together to learn from each other and try to choose the best way to balance the time it takes to compile native code against the time it takes to interpret the executing code directly. Today, The performance of Java programs has changed so much that it can compete with C/C++ programs

5.2 The need for interpreters remains

  • First, after the program is started, the interpreter can come into play immediately, saving compilation time and executing immediately
  • For a compiler to be effective, it takes a certain amount of execution time to compile code into native code. But it is more efficient when compiled into native code
  • For server applications, startup time is not a major concern, but for application scenarios where startup time is important, a balance needs to be struck
  • When the Java virtual machine starts up, the interpreter can take effect first, rather than waiting for the compiler to complete compilation, which saves a lot of unnecessary compilation time. Over time, the compiler takes effect, compiling more and more code into native code for more efficient execution
  • At the same time, explain execution acts as the compiler’s “escape door” when aggressive optimization by the compiler fails.

Question: Does a program just started perform the same as a program that has been running for a while?

In production environment publishing, publishing is done in batches, divided into batches based on the number of machines, with each batch accounting for up to 1/8 of the cluster. There has been such a case of failure: a programmer in the publishing platform to publish in batches, when entering the total number of batches, mistakenly fill in the component as two batches. Under normal circumstances, half of the machines can barely handle traffic, but because the JVM that has just started is interpreted execution, hot code statistics and JIT dynamic compilation have not been carried out, resulting in the machine startup, the current half of the successful release of the server immediately down, this failure indicates the existence of JIT. Ali Team

5.3 JIT compiler

5.3.1 Concept Explanation

  • The “compiler” of the Java language is an “indeterminate” operation, as it may refer to the process by which a front-end compiler (a “compiler front end” is more accurate) converts a. Java file into a. Class file. For example: Sun’s Javac
  • It may also refer to the process by which the virtual machine’s back-end run Time (JIT) Compiler (Just In Time Compiler) converts bytecode into machine code. For example: hotSpot’s C1,C2 compiler
  • It may also refer to the process Of compiling. Java files directly into native machine code using a static AOT Compiler (Ahead Of Time Compiler).

5.3.2 Hotspot code and detection mode

  • Bytecode that needs to be compiled into native code, also known as hotspot code, depending on how often the code is called for execution
  • A method that is called more than once, or a method body that loops more than once, can be called hot code
  • The JIT compiler deeply optimizes frequently invoked hot code at run time, compiling it directly into local machine instructions for the corresponding platform. This improves the performance of Java programs
  • Therefore, local machine instructions can be compiled by the JIT compiler. Since this compilation method takes place during the execution of the method, it is also known as on-stack Replacement, OSR On Statck Replacement
  • How many times does a method have to be called, or how many times does a loop body have to execute a loop to meet this standard? There must be an explicit threshold for the JIT compiler to compile this “hot code” for execution by local machine instructions. The hotspot detection function is mainly relied on here
  • HotSpot detection currently adopted by HotSpot VM is HotSpot detection based on counters
  • With Counter based HotSpot detection, HotSpot VM will set up two different types of counters for each method: method Invocation Counter and BackEdge Counter
    • A method call counter counts the number of times a method is called
    • A loopback counter is used to count the number of loops executed by the body of the loop

Method call counter

  • This counter is used to count the number of times a method is called, and its default threshold is in Client mode

1500 times and 10000 times in Server mode. Above this threshold, JIT compilation is triggered.

  • This threshold can be set manually using the VM parameter XX: CompileThreshold.
  • When a method is called, it is checked to see if a JIT-compiled version of the method exists, for example

If it does, the compiled native code is preferred. If no compiled version exists, the call counter value of this method is incremented by one, and the method call counter and the return counter value are determined to exceed the threshold of the method call counter. If the threshold is exceeded, a code compilation request for the method is submitted to the just-in-time compiler

Back edge counter

  • The function is to count the number of times the loop body code in a method is executed. The instruction that controls the flow forward in the bytecode is called the “Back Edge”. Obviously, the purpose of setting up the back counter statistics is to trigger OSR compilation

Heat attenuation

  • When a certain time limit is exceeded, a method’s call Counter is reduced by half if it hasn’t been called enough times to commit to the just-in-time compiler, a process called Counter Decay. This period is called the Counter Half Life Time counted by this method.
  • Heat decay happens while the virtual machine is garbage collecting. Using the virtual machine parameter -xx: -usecounterdecay can turn heat decay off and let the method counter count the absolute number of method calls so that most methods will be compiled into local code if the system runs long enough
  • Alternatively, you can use the -xx: CounterHalfLifeTime parameter to set the time of the half-decay period in seconds

6 HotSpot VM can set the application execution mode

By default HotSpot VM uses an interpreter and just-in-time compiler architecture

  • -Xint: executes programs in interpreter mode.
  • -xcomp: executes programs in real-time compiler mode. If just-in-time compilation fails, the interpreter steps in
  • -Xmixed: executes programs in interpreter + just-in-time compiler mode

7 Test interpreter mode and JIT compilation mode

/** * Test interpreter mode and JIT compilation mode * -xint: 6520ms * -xcomp: 950ms * -xmixed: 936ms */ public class IntCompTest { public static void main(String[] args) { long start = System.currentTimeMillis(); testPrimeNumber(1000000); long end = System.currentTimeMillis(); System.out.println(" + (end-start)); } public static void testPrimeNumber(int count){ for (int i = 0; i < count; I++) {// count prims up to 100. j <= 100; j++){ for(int k = 2; k <= Math.sqrt(j); k++){ if(j % k == 0){ continue label; } } //System.out.println(j); }}}}Copy the code

8 JIT classification in HotSpot VM

There are two JIT compilers embedded in HotSpot VM, called Client Compiler and Server Compiler, but in most cases we call them simply C1 Compiler and C2 Compiler

  • -client: specifies that the Java VM runs in client mode and uses the C1 compiler
    • The C1 compiler optimizes bytecode simply and reliably, in a short time. For faster compilation
  • -server: specifies that the Java VM runs in server mode and uses the C2 compiler
    • C2 performs lengthy optimizations, as well as aggressive optimizations. But optimized code execution is more efficient

C1 and C2 compilers have different optimization strategies

  • The C1 compiler mainly has methods inlining, de-virtualization and redundancy elimination
    • Method inlining: Compiles the referenced function code to the reference point, which reduces stack frame generation, parameter passing, and jump
    • De-virtualization: Inline unique implementation classes
    • Redundancy elimination: Fold out some code that will not execute at run time
  • The optimization of C2 is mainly at the global level, and escape analysis is the basis of optimization
    • Scalar substitution: The substitution of an aggregate object’s property value with a scalar value
    • Stack allocation: For unescaped objects, allocate objects on the stack instead of the heap
    • Synchronization elimination: To clear a synchronization operation, usually synchronized

After Java7, once a developer explicitly specifies the command “one server” in a program, the hierarchical compilation strategy is turned on by default, with the C1 and C2 compilers working together to perform compilation tasks

conclusion

  • In general, jIT-compiled machine code performs better than the interpreter
  • The startup time of C2 compiler is slower than that of C1 compiler, and the execution speed of C2 compiler is much faster than that of C1 compiler after the system is stably executed

Graal compilers versus AOT compilers

Graal compiler

  • Since JDK10 HotSpot has added a new just-in-time compiler: the Graal compiler
  • The compilation effect was reviewed for the C2 compiler in just a few years. It should be a future
  • At present, with the state of “experiment” label, you need to use the switch parameters – XX: + UnlockExperimentalVMOptions a XX: + UseJVMCICompiler to activate, just can use
  • Java programming

The AOT compiler

  • AOT Compiler is introduced in JDK9 (static Ahead Of Time Compiler)
  • AOT compilation is the opposite of just-in-time compilation. As we know, just-in-time compilation refers to the process of converting bytecode into machine code that can be run directly on the hardware while the program is running and deployed to a managed environment. AOT compilation refers to the process of converting bytecode to machine code before the program is run
  • Benefits: Java virtual machine loading is precompiled into a binary library and can be performed directly. No need to wait for the just-in-time compiler to warm up, reducing the “first-run slow” experience of Java applications
  • Cons: Broken Java “compile once, run anywhere”, must compile distribution for each different hardware, oS,

Reduces the dynamic nature of the Java linking process, and the loaded code must all be known at compile time


JVM full directory

Class loading mechanism 3. Runtime data area [PC register, vm stack, local method stack] 4. Runtime data area [heap] 5. Runtime data area [method area] 6. Temporary absence 7. Runtime data area [instantiated memory layout and access location of objects, direct memory] 8. String constant pool 10. Garbage collection [overview, related algorithms] 11. Garbage collection [related concepts] 12. Common OOM 14. JDK command line tools