This article is participating in “Java Theme Month – Java Development Practice”, for details: juejin.cn/post/696826…

This is the first day of my participation in Gwen Challenge

Ideological motivation

Don’t think you’re better than everyone else, even if you’re good.

If the profile

The interpreter

Java programs are initially interpreted through the Interpreter, and when the virtual machine detects that a method or block of code is being run particularly frequently, it identifies that code as “hotspot code.” Because of this, our hotspot VIRTUAL machine got its name.

Interpreter advantages

  • Explain execution takes up less memory space.

  • (Faster startup and first execution) When the program needs to be started quickly, the interpreter can take over first, saving compilation time and executing immediately.

  • (Improved dynamic and portability) When under the dynamic effect of the program, if all the relevant static native code has been pre-compiled, it will not be able to achieve dynamic extension and improve the ability to port to other computer platform architectures


The compiler

To improve the efficiency of hot code execution, the just-in-time Compiler (JIT) compiles the code into local platform-specific machine code at run Time and performs various levels of optimization.

Compiler advantages

  • As the program runs, the compiler comes into play over time, compiling more and more code into native code for more efficient execution.

  • (Reverse optimization) At the same time, when aggressive optimization by the compiler fails, it can also reverse optimization to restore the interpreted execution.

Therefore, the interpreter and compiler often work together throughout the virtual machine execution architecture, as shown in the figure below.

An interpreter and compiler architecture (process)

  1. If a Java program needs to be started and executed quickly, or only once, the interpreter can take effect first, saving compilation time. After the program is run, the JIT compiler comes into play over time, compiling more and more code into native code for more efficient execution.

  2. When the program is running in an environment where memory resources are limited (such as some embedded systems), the interpreted execution can be used to save memory; otherwise, JIT compilation execution can be used to improve efficiency

  3. The interpreter can also serve as an escape door for JIT compiler aggressive optimizations, allowing the compiler to select optimizations that will improve performance most of the time based on probability, and then fall back to the explanatory state through Deoptimization when the assumption of aggressive optimizations fails

Therefore, the interpreter and compiler often work together throughout the virtual machine execution architecture

  • Xint Settings: By using the -xint parameter, Interpreted Mode can be forced and the compiler is completely irrelevant.

  • -Xcomp: Forces the VM to run in Compiled Mode. In this case, Compiled Mode takes precedence, but the interpreter still has to enter the execution if compilation cannot take place.

  • -xmixed setting: This Mixed Mode is called “Mixed Mode”,

You can run the VM -version command to view the current default operating mode.

Just-in-time compiler (JIT compiler)

JIT compiler is not a necessary part of virtual machine, but the compilation performance of JIT compiler and the level of code optimization is one of the most critical indicators to measure the excellence of a commercial virtual machine. It is also the core part of virtual machine and can best reflect the technical level of virtual machine.

The compiled object and the trigger condition

There are two types of “hot code” that are compiled on the fly, namely:

The target object for compilation

  • A method that is called multiple times
    • The compiler treats the entire method as a compilation object, which is standard JIT compilation
  • The body of a loop that is executed multiple times
    • From the body of the loop, but the compiler will still use the entire method as the compilation object because it occurs during method execution, called on-stack substitution.

Judge hotspot code

“To determine whether a piece of code is Hot code and whether it needs to be compiled immediately”, such behavior is called Hot Spot Detection. There are two Detection algorithms:

Sample Based Hot Spot Detection

The virtual machine periodically checks the top of each thread’s stack, and if a method appears frequently at the top of the stack, it is a “hot method.”

  • Advantages: Simple implementation, efficient, easy to get method call relationships.

  • Disadvantages: Difficult to identify method reduce(decay), vulnerable to thread blocking or other external disturbances.


Counter Based Hot Spot Detection

Set up counters for each method (even a block of code) that executes more than a threshold and is considered a “hot method.”

  • Advantages: accurate and rigorous statistical results.

  • Disadvantages: cumbersome implementation, can not directly get method call relationship.

HotSpot uses the second type – HotSpot detection based on technology and has two types of counters:

  • Invocation Counter

  • Back Edge Counter


Two just-in-time compilers

As you can see from the interpreter and Compiler collaboration architecture diagram above, the JVM virtual machine implements two different JIT compilers, called Client and Server Compiler, or simply C1 and C2 compilers.

Threshold of hotspot triggering

Both of these counters have a certain threshold, which triggers JIT compilation, as detailed below.

The following two hot spot detection counters are mentioned above:

Invocation Counter
  • The first is the method call counter:

    • In Client mode, the default threshold is 1500.

    • In Server mode, the number is 10000.

    • This threshold can be set manually by passing -xx: CompileThreshold.

  • If nothing is done, a method call counter counts not the absolute number of times a method is called, but a relative frequency of execution, the number of times a method is called over a period of time. (Can be understood as a sliding window).

  • When a certain time limit is exceeded, the method’s call Counter is reduced by half if the method hasn’t been called enough times to commit to the just-in-time compiler, a process called Counter Decay. This period of Time becomes the statistical Counter Half Life Time of this method.

  • You can use the VM parameter -xx: CounterHalfLifeTime to set the time of the half-age period (in seconds). The entire JIT-compiled interaction is shown below.


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. For this counter threshold, HotSpot provides -xx: BackEdgeThreshold for the user to set.

However, the current VM uses -xx: OnStackReplacePercentage to change the threshold. The calculation formula is as follows:

  • Client mode, the formula is CompileThreshold X OSR ratio (OnStackReplacePercentage) /100. Where the OSR ratio defaults to 933, then the threshold of the back counter is 13995.

  • Server mode, the formula for the method call counter threshold (the Compile Threashold) X (OSR (OnStackReplacePercentage) – interpreter monitoring ratio (InterpreterProfilePercent)) / 100

Including onStackReplacePercentage the default value is 140, InterpreterProfilePercentage defaults to 33, if all the default values, then the Server mode virtual machine back to the side counter threshold for 10700.

The build process

By default, both just-in-time compile requests from method calls and OSR requests will continue to be interpreted by the virtual machine until the code compiler completes, while the compile action takes place in the background compilation thread.

The user can disable BackgroundCompilation with the -xx: -backgroundcompilation parameter, so that once the JIT compilation condition is met, the executing thread submits the request to the virtual machine and waits until the compilation process is complete before starting to execute the native code output by the compiler.

Vm running mode

The current HotSpot compiler works by default with the interpreter and one of the just-in-time compilers. Depending on the mode in which the virtual machine is running, the HotSpot virtual machine automatically selects a mode based on its version and the hardware capabilities of the machine. You can also use the -client and -server parameters to force a VM to run in client or server mode.

Client Compiler:

It is a simple and fast three-step compiler that focuses on local optimization and abandons many time-consuming global optimization methods.

  • In the first phase, a platform-independent front end constructs bytecode into a high-level Intermediate Representation (HIR) of code. Before that, the compiler performs some basic optimizations on the bytecode, such as method inlining, constant propagation, and so on.

  • In the second stage, a platform-dependent back end generates low-level Intermediate Representation (LIR) from the HIR, before other optimizations such as null-check elimination, range-check elimination, and so on are performed on the HIR. Make HIR more efficient.

  • In the third stage, registers are allocated on the LIR using Linear Scan Register Allocation on the platform-dependent back end, Peephole optimization is performed, and machine code is generated.

Server Compiler:

The compiler that is tailored for typical server applications and configured specifically for server performance is also a fully optimized advanced compiler that performs all classic optimizations with nearly the same intensity as the GNU C++ compiler with the -02 parameter.

  • Dead Code Elimination

  • LoopcUnrolling,

  • In the case of Loop Expression control,

  • Common Subexpression Elimination,

  • Constant Propagation,

  • Basic Block Reordering

Some optimization techniques closely related to Java language features are also implemented, such as

  • Range Check Elimination,

  • Null Check Elimination

It is also possible to make some unstable radical optimizations based on performance monitoring information provided by the interpreter or Client Compiler, such as

  • “Guarded Inlining”,

  • Branch Frequency Prediction, etc

  • The register allocator in Server Compiler is a global graph coloring allocator that takes advantage of large register collections on some processor architectures, such as RISC

The compilation speed is much faster than that of traditional static optimized compilers, and the code quality is improved compared with that of Client Compiler, which can reduce the local code execution time and offset the extra compilation time cost

How do I observe the compilation process and results of a real-time compiler from the outside?

  • -xx :+PrintCompilation prints the method name of the compiled code when compiling in real time

  • -xx :+PrintInlining Outputs method inline information when compiling instantaneously

  • – XX: + PrintAssembly in real-time at compile time, print method of assembly code is compiled, the virtual machine should be installed the disassembly adapter HSDIS plug-ins, Product parameters are necessary for the virtual machine – XX: + UnlockDiagnosticVMOptions open virtual machine diagnosis model

  • -xx :+PrintOptoAssembly is used for the Server VM to print an intermediate code representation that is closer to the final result and does not require HSDIS plug-in support

  • -xx :+PrintLIR is used for Client VM to output intermediate code representation that is close to the final result and does not require HSDIS plug-in support

  • -xx :+PrintCFGToFile Is used in the Client Compiler to output the data (such as bytecode, HIR generation, LIR generation, register allocation process, local code generation, etc.) in the compilation process to the file

  • -xx :PrintIdealGraphFile is used in the Server Compiler to output the data (such as bytecode, HIR generation, LIR generation, register allocation process, local code generation, etc.) in the compilation process to the file

Note to export CFG or IdealGraph files, the VM of the Product version must support the Debug or FastDebug version. The VM of the Product version cannot export these files