Tuning of JIT (Just-In-Time) compiler can be done by:
1. Enable JIT logging
By enabling JIT logs, you can observe which code is compiled and the specific behavior of optimization. The startup parameters are as follows:
-XX:+UnlockDiagnosticVMOptions -XX:+PrintCompilation
This outputs detailed information about JIT compilation, including compilation sequence number, compilation level, and method information.
2. Optimize hotspot code
Find frequently executed hotspot codes through performance analysis tools and optimize their logic. For example:
Hot code rewrite: Rewrite complex calculation methods into more efficient implementations.
Simplify branch logic: Reduce the number of branches in the code and avoid excessive conditional judgments.
3. Circular expansion
Expand the commonly used code in the loop to reduce branch judgments and jumps in the loop body. For example:
public class LoopUnrollingDemo { public static void main(String[] args) { int sum = 0; for (int i = 0; i < 10; i++) { // JIT will try to expand a small-scale loop sum += i; } ("sum:" + sum); } }
Loop expansion reduces the number of iterations of the loop and the overhead of branch prediction.
public static void main(String[] args) { int sum = 0; // Divide the loop into two parts for (int i = 0; i < 10; i += 2) { // Add 2 each time sum += i; sum += (i + 1); } ("sum:" + sum); }
4. Inline optimization
Insert small method bodies that are frequently called directly to the calling point to reduce the overhead of method calls. For example:
public class InlineDemo { public static void main(String[] args) { long start = (); for (int i = 0; i < 1_000_000; i++) { add(1, 2); // Small methods will be inlined by JIT } long end = (); ("Execution time:" + (end - start) / 1_000_000 + " ms"); } static int add(int a, int b) { return a + b; } }
Inline optimization can significantly reduce the number of function calls and the overhead of stack operations.
public static void main(String[] args) { long start = (); int sum = 0; for (int i = 0; i < 1_000_000; i++) { sum += (1 + 2); // The add method is directly inlined } long end = (); ("Execution time:" + (end - start) / 1_000_000 + " ms"); ("sum:" + sum); }
5. Escape Analysis
Identify the situation where the local object does not escape the method through escape analysis, and allocate it on the stack instead of the heap. This can reduce the overhead of memory allocation and recycling and improve memory access efficiency.
6. Use performance analysis tools
-
Java Mission Control (JMC): Used to analyze application performance, thread activity, and garbage collection behavior. Launch the app and enable Java Flight Recorder (JFR):
java -XX:StartFlightRecording=duration=60s,filename= MyApp
Open with JMC
Files, analyzing hot codes and resource usage.
-
VisualVM: Provides real-time monitoring of thread, memory and method calls. Add the following parameters when starting the application:
-
Open VisualVM, connect to the target JVM, and view thread and memory activity.
7. Adjust JIT parameters
-
Compile threshold: Adjust the threshold value for the method being compiled, for example:
-XX:CompileThreshold=1000
This will set the method to be called 1000 times before it triggers the compilation.
-
Number of compile threads: Adjust the number of threads used by the JIT compiler, for example:
-XX:ParallelGCThreads=4
This will set the number of parallel compilation threads to 4.
8. Reduce the creation of short life cycle objects
A large number of short life cycle objects will increase the pressure of garbage collection and affect performance. Object creation can be reduced through object pooling and other methods.
Through the above methods, the behavior of the JIT compiler can be effectively optimized and the performance of Java applications can be improved.
This is the end of this article about the implementation of java JIT tuning. For more related java JIT tuning content, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!