[In-depth understanding of the just-in-time compiler of the Java virtual machine] 1141 compiler optimization technology

I. Overview

1. Although the goal of the compiler is to translate program code into local machine code, the difficulty is not whether the machine code can be successfully translated. The quality of output code optimization is the key to determining whether the compiler is good or not. .

2. Overview of optimization technology

1. On the official Wiki of OpenJDK, the HotSpot virtual machine design team has listed a relatively comprehensive list of optimization techniques used in the just-in-time compiler.
Insert picture description here

Insert picture description here

Insert picture description here

2. The optimization and transformation of these codes by the just-in-time compiler is based on the intermediate representation of the code or the machine code, not directly on the Java source code.

3. Various compilers generally put inline optimization at the top of the optimization sequence.

Three, four representative optimization technology learning

1. One of the most important optimization techniques: method inlining.

2. One of the most cutting-edge optimization technologies: escape analysis.

3. One of the classic language-independent optimization techniques: common sub-expression elimination.

4. One of the classic optimization techniques related to language: array boundary check elimination.

Four, method inlining

1. Inlining is dubbed the mother of optimization in the industry, because in addition to eliminating the cost of method calls, it is more important to establish a good foundation for other optimization methods.

2. Without inlining, most other optimizations cannot be performed effectively.

3. There is no difficulty in understanding the optimization behavior of method inlining, that is, "copy" the code of the target method intact into the method that initiated the call to avoid actual method calls.

4. When the Java method is parsed and dispatched

A: Only private methods, instance constructors, superclass methods and static methods called using the invokestatic instruction that are called using the invokespecial instruction will be resolved at compile time. In addition to the above four methods (at most, the special case of the final modified method is removed, although it is called using the invokevirtual instruction, it is also a non-virtual method.

B: The default instance method in the Java language is a virtual method

5. How does the Java virtual machine solve the inline problem of virtual methods in the virtual machine?

A: A technology called Class Hierarchy Analysis (CHA) is introduced, which is a type analysis technology within the scope of the entire application, used to determine whether an interface is available in the currently loaded class More than one implementation, whether a certain class has subclasses, whether a certain subclass covers a certain virtual method of the parent class, etc.

B: When the compiler performs inlining, it will take different treatments according to different situations: if it is a non-virtual method, then it can be directly inlined. This kind of inlining is 100% safe; if it is encountered Virtual method, it will query CHA whether this method really has multiple target versions to choose from in the current program state. If there is only one version in the query, then you can assume that "the whole picture of the application is what it is currently running" To perform inlining, this kind of inlining is called Guarded Inlining.

C: Since the Java program is dynamically connected, it is uncertain when it will be loaded into the new type to change the CHA conclusion. Therefore, this kind of inlining is a radical predictive optimization, and the "escape door" must be reserved, that is, when assuming "Slow Path" when the condition is not met. If in the subsequent execution of the program, the virtual machine has not been loaded into the class that will change the inheritance relationship of the receiver of this method, then this inline optimized code can be used forever. If a new class that causes a change in the inheritance relationship is loaded, then the compiled code must be discarded, returned to the interpreted state for execution, or recompiled.

6. Inline buffering

A: The inline cache is a cache built before the normal entry of the target method. Its working principle is roughly as follows: before the method call occurs, the inline cache state is empty. When the first call occurs, the cache records the method Receiver's version information, and compare the receiver's version every time a method is called.

B: If the receiver version of each incoming method is the same, then it is a monomorphic inline cache (Monomorphic Inline Cache). Calling through this cache only requires one more type determination overhead than using non-virtual method calls that are not inlined.

C: If the method receivers are really inconsistent, it means that the program uses the polymorphic characteristics of the virtual method. At this time, it will degenerate into a Megamorphic Inline Cache (Megamorphic Inline Cache), and its cost is equivalent to finding the virtual method. Table for method dispatch.

Five, escape analysis

Escape Analysis is a cutting-edge optimization technology in the current Java virtual machine. Like type inheritance analysis, it is not a means of directly optimizing code, but an analysis technology that provides a basis for other optimization measures.

2. The basic principle is: Analyze the dynamic scope of an object. When an object is defined in a method, it may be referenced by an external method, such as being passed as a call parameter to other methods. This is called method escape; even It may be accessed by external threads, such as assigning values ​​to instance variables that can be accessed in other threads. This is called thread escape; never escapes, method escapes to thread escapes, which are called different degrees of object escape from low to high.

3. If it can be proved that an object will not escape outside the method or thread (in other words, other methods or threads cannot access the object in any way), or the degree of escape is relatively low (only escape from the method and not escape) Out of the thread), you may take different degrees of optimization for this object instance

A: Stack Allocations [illustration] (Stack Allocations): In the Java virtual machine, the memory space for creating objects is allocated on the Java heap. The objects in the Java heap are shared and visible to each thread, as long as the object is held Reference, you can access the object data stored in the heap. The garbage collection subsystem of the virtual machine will reclaim objects that are no longer used in the heap, but the reclaiming action requires a lot of resources to be consumed whether it is marking and filtering out recyclable objects or reclaiming and arranging memory. If it is determined that an object will not escape from the thread, it would be a very good idea to let this object allocate memory on the stack, and the memory space occupied by the object can be destroyed when the stack frame is popped. In general applications, the proportion of local objects that will not escape at all and those that will not escape the thread is very large. If stack allocation can be used, a large number of objects will be automatically destroyed as the method ends. , The pressure on the garbage collection subsystem will drop a lot.Allocation on the stack can support method escape, but not thread escape

B: Scalar Replacement: If a data can no longer be decomposed into smaller data to represent, the primitive data types in the Java virtual machine (numerical types such as int, long, and reference types, etc.) cannot be further decomposed , Then these data can be called scalar. In contrast, if a piece of data can continue to be decomposed, it is called Aggregate. Objects in Java are typical aggregates. If a Java object is disassembled, and the member variables used in it are restored to the original type for access according to the access of the program, this process is called scalar substitution. If the escape analysis can prove that an object cannot be accessed outside the method, and the object can be disassembled, then the program may not create the object when the program is actually executed, but directly create several of its members used by this method. Variables instead. After the object is split, in addition to allowing the member variables of the object to be allocated and read and written on the stack (data stored on the stack is likely to be allocated by the virtual machine to the high-speed registers of the physical machine for storage), it can also be used for subsequent Further optimization means create conditions. Scalar replacement can be regarded as a special case of allocation on the stack, and the implementation is simpler (don't consider the allocation of the complete structure of the entire object), butThe requirements for the degree of escape are higher, it does not allow the object to escape from the scope of the method

C: Synchronization Elimination: Thread synchronization itself is a relatively time-consuming process. If escape analysis can determine that a variable will not escape the thread and cannot be accessed by other threads, then the read and write of this variable will definitely not happen Competition, synchronization measures implemented on this variable can be safely eliminated.

4. The computational cost of escape analysis is very high, and there is even no guarantee that the performance benefits of escape analysis will exceed its consumption. If you want to determine with 100% accuracy whether an object will escape, a series of complex data flow-sensitive inter-procedural analysis is required to determine the impact of each branch of the program on the object during execution.

5. You can use the parameter -XX:+DoEscapeAnalysis to manually start the escape analysis. After opening, you can use the parameter -XX:+PrintEscapeAnalysis to view the analysis results. With escape analysis support, users can use the parameter -XX:+EliminateAllocations to enable scalar replacement, +XX:+EliminateLocks to enable synchronization elimination, and use the parameter -XX:+PrintEliminateAllocations to view the scalar replacement.

6. Escape analysis technology will definitely support a series of more practical and effective optimization technologies.

Six, common subword expression elimination

1. Common sub-expression elimination is a very classic optimization technique commonly used in various compilers. Its meaning is: if an expression E has been calculated before, and from the previous calculation to the current E The value of all the variables in has not changed, so this occurrence of E is called a common sub-expression.

2. For this kind of expression, there is no need to spend time to recalculate it, just directly replace E with the result of the previously calculated expression. If this kind of optimization is limited to the basic block of the program, it can be called Local Common Subexpression Elimination. If the scope of this kind of optimization covers multiple basic blocks, it is called a global common subexpression. Elimination (Global Common SubexpressionElimination).

Seven, array boundary check elimination

1. Array Bounds Checking Elimination is a classic language-related optimization technique in just-in-time compilers.

When accessing the array element foo[i] in the Java language, the system will automatically check the upper and lower bounds, that is, i must satisfy the access condition of "i>=0&&i<foo.length", otherwise a runtime exception will be thrown : Java.lang.ArrayIndexOutOfBoundsException. This is a very friendly thing for software developers. Even if the programmer does not specifically write defensive code, most overflow attacks can be avoided. But for the execution subsystem of the virtual machine, every time an array element is read and written, there is an implicit conditional judgment operation. For program codes with a large number of array accesses, this must be a performanceburden

2. Autobox Elimination, Safepoint Elimination, Dereflection, etc.

Guess you like

Origin blog.csdn.net/qq_40996741/article/details/109153641