第11章 后端编译与优化 - 代码指南
1. 代码结构
后端编译与优化相关代码位于 linsir-abc-core/src/main/java/com/linsir/abc/core/jvm/runtime/ 目录下,按照功能分为四个子包:
jvm/runtime/
├── jit/ # JIT即时编译相关
│ ├── HotSpotDetector.java # 热点代码探测演示
│ ├── JITAnalysisDemo.java # JIT编译分析演示
│ └── TieredCompilationDemo.java # 分层编译演示
├── aot/ # AOT提前编译相关
│ ├── AOTCompilationDemo.java # AOT编译演示
│ └── AOTPerformanceTest.java # AOT性能测试
├── optimization/ # 编译器优化技术
│ ├── MethodInliningDemo.java # 方法内联演示
│ ├── EscapeAnalysisDemo.java # 逃逸分析演示
│ └── LoopOptimizationDemo.java # 循环优化演示
└── graal/ # Graal编译器
├── GraalCompilerDemo.java # Graal编译器演示
└── GraalPerformanceTest.java # Graal性能测试测试类位于 linsir-abc-core/src/test/java/com/linsir/abc/core/jvm/runtime/RuntimeCompilationTest.java
2. 代码作用
2.1 JIT编译相关 (jit包)
HotSpotDetector.java
- 作用:演示JVM如何探测热点代码并触发JIT编译
- 核心功能:
hotMethod(): 热点方法演示,会被JIT编译器识别并编译triggerOSR(): 触发OSR(栈上替换)编译,针对循环体热点computeIntensive(): 计算密集型任务,展示JIT优化效果
JITAnalysisDemo.java
- 作用:分析JIT编译过程和性能特点
- 核心功能:
- 计算方法执行时间对比(解释执行 vs JIT编译后)
- 斐波那契数列递归与迭代版本性能对比
- 矩阵乘法计算演示
TieredCompilationDemo.java
- 作用:演示分层编译的五个层级
- 核心功能:
- 模拟第0层(解释执行)到第4层(C2优化编译)
- 展示不同编译层级的优化策略
- 编译阈值和计数器机制说明
2.2 AOT编译相关 (aot包)
AOTCompilationDemo.java
- 作用:演示AOT(Ahead-of-Time)提前编译
- 核心功能:
- 展示AOT编译的基本用法
- 生成Jaotc编译命令文件
- 对比AOT与JIT的启动时间和内存占用
AOTPerformanceTest.java
- 作用:AOT与JIT性能对比测试
- 核心功能:
- 矩阵乘法性能测试
- 素数计算性能测试
- 字符串处理性能测试
- 集合操作性能测试
- 排序算法性能测试
2.3 编译器优化技术 (optimization包)
MethodInliningDemo.java
- 作用:演示方法内联优化
- 核心功能:
- 展示内联前后的代码差异
- 内联深度限制演示
- 内联性能对比测试
EscapeAnalysisDemo.java
- 作用:演示逃逸分析及相关优化
- 核心功能:
- 无逃逸对象(栈上分配/标量替换)
- 方法逃逸对象
- 线程逃逸对象
- 同步消除(锁消除)
- 标量替换性能测试
- 栈上分配性能测试
LoopOptimizationDemo.java
- 作用:演示循环优化技术
- 核心功能:
- 循环展开(Loop Unrolling)
- 循环不变量外提(Invariant Code Motion)
- 边界检查消除(Bounds Check Elimination)
- 向量化优化(SIMD)
- 性能对比测试
2.4 Graal编译器 (graal包)
GraalCompilerDemo.java
- 作用:演示Graal编译器特性
- 核心功能:
- 检测是否使用Graal编译器
- 部分逃逸分析(Partial Escape Analysis)
- Graal编译器使用指南
- 性能测试
GraalPerformanceTest.java
- 作用:Graal编译器性能测试
- 核心功能:
- 快速排序算法测试
- 素数筛法测试
- 矩阵乘法测试
- 蒙特卡洛计算PI
- 斐波那契数列计算
- 字符串处理测试
- 对象创建测试
3. 测试方法
3.1 运行所有测试
bash
cd linsir-abc/linsir-abc-core
mvn test -Dtest=RuntimeCompilationTest3.2 测试类说明
测试类 RuntimeCompilationTest.java 包含12个测试方法:
| 序号 | 测试方法 | 说明 |
|---|---|---|
| 1 | testHotSpotDetection | 测试热点代码探测 |
| 2 | testJITAnalysis | 测试JIT分析方法 |
| 3 | testTieredCompilation | 测试分层编译模拟 |
| 4 | testAOTCompilation | 测试AOT编译方法 |
| 5 | testAOTPerformance | 测试AOT性能测试类 |
| 6 | testMethodInlining | 测试方法内联 |
| 7 | testEscapeAnalysis | 测试逃逸分析 |
| 8 | testLoopOptimization | 测试循环优化 |
| 9 | testGraalCompiler | 测试Graal编译器检测 |
| 10 | testGraalPerformance | 测试Graal性能测试类 |
| 11 | testAllOptimizations | 测试所有编译优化技术 |
| 12 | testPerformanceComparison | 测试性能对比 |
3.3 单独运行演示类
JIT编译演示
bash
mvn exec:java -Dexec.mainClass="com.linsir.abc.core.jvm.runtime.jit.HotSpotDetector"
mvn exec:java -Dexec.mainClass="com.linsir.abc.core.jvm.runtime.jit.JITAnalysisDemo"
mvn exec:java -Dexec.mainClass="com.linsir.abc.core.jvm.runtime.jit.TieredCompilationDemo"AOT编译演示
bash
mvn exec:java -Dexec.mainClass="com.linsir.abc.core.jvm.runtime.aot.AOTCompilationDemo"
mvn exec:java -Dexec.mainClass="com.linsir.abc.core.jvm.runtime.aot.AOTPerformanceTest"编译器优化演示
bash
mvn exec:java -Dexec.mainClass="com.linsir.abc.core.jvm.runtime.optimization.MethodInliningDemo"
mvn exec:java -Dexec.mainClass="com.linsir.abc.core.jvm.runtime.optimization.EscapeAnalysisDemo"
mvn exec:java -Dexec.mainClass="com.linsir.abc.core.jvm.runtime.optimization.LoopOptimizationDemo"Graal编译器演示
bash
mvn exec:java -Dexec.mainClass="com.linsir.abc.core.jvm.runtime.graal.GraalCompilerDemo"
mvn exec:java -Dexec.mainClass="com.linsir.abc.core.jvm.runtime.graal.GraalPerformanceTest"3.4 使用不同JVM参数测试
查看JIT编译日志
bash
java -XX:+PrintCompilation -cp target/classes com.linsir.abc.core.jvm.runtime.jit.HotSpotDetector禁用分层编译
bash
java -XX:-TieredCompilation -cp target/classes com.linsir.abc.core.jvm.runtime.jit.TieredCompilationDemo使用Graal编译器(需GraalVM)
bash
java -XX:+UnlockExperimentalVMOptions -XX:+UseJVMCICompiler -cp target/classes com.linsir.abc.core.jvm.runtime.graal.GraalCompilerDemo查看逃逸分析优化
bash
java -XX:+DoEscapeAnalysis -XX:+EliminateAllocations -XX:+PrintEscapeAnalysis -cp target/classes com.linsir.abc.core.jvm.runtime.optimization.EscapeAnalysisDemo4. 代码执行预期结果
4.1 测试执行结果
运行 mvn test -Dtest=RuntimeCompilationTest 预期输出:
[INFO] Tests run: 12, Failures: 0, Errors: 0, Skipped: 0
[INFO] BUILD SUCCESS性能对比输出示例:
性能对比(10000次迭代):
JIT风格: 4 ms
AOT风格: 3 ms
Graal风格: 45 ms4.2 HotSpotDetector 执行结果
=== 热点代码探测演示 ===
热点方法执行 1000 次
热点方法执行 10000 次
普通方法执行
OSR result: 333833500
=== 演示完成 ===
提示: 使用 -XX:+PrintCompilation 查看编译日志4.3 JITAnalysisDemo 执行结果
=== JIT编译分析演示 ===
测试1: 简单计算
计算结果: 328350
执行时间: 0 ms
测试2: 斐波那契数列
递归版本(30): 832040, 耗时: 5 ms
迭代版本(30): 832040, 耗时: 0 ms
测试3: 矩阵乘法
矩阵大小: 100x100
计算结果: 24502500
执行时间: 2 ms
=== 演示完成 ===4.4 TieredCompilationDemo 执行结果
=== 分层编译演示 ===
编译层级说明:
第0层: 解释执行
第1层: C1简单编译
第2层: C1受限编译
第3层: C1完全编译
第4层: C2优化编译
模拟分层编译过程:
第0层 - 解释执行: 结果 = 4950
第1层 - C1简单编译: 结果 = 4950
第2层 - C1受限编译: 结果 = 4950
第3层 - C1完全编译: 结果 = 4950
第4层 - C2优化编译: 结果 = 4950
=== 演示完成 ===4.5 EscapeAnalysisDemo 执行结果
=== 逃逸分析演示 ===
无逃逸对象示例:
结果: 25
说明: Point对象未逃逸,可进行栈上分配和标量替换
方法逃逸示例:
结果: Point(3, 4)
说明: Point对象逃逸到方法外部,必须在堆上分配
同步消除示例:
结果长度: 80
说明: StringBuffer的同步操作被消除
性能测试:
标量替换测试: 耗时 5 ms
栈上分配测试: 耗时 3 ms
同步消除测试: 耗时 8 ms
=== 演示完成 ===
提示: 使用 -XX:+DoEscapeAnalysis 启用逃逸分析4.6 LoopOptimizationDemo 执行结果
=== 循环优化演示 ===
循环展开示例:
基础循环: 15
展开循环: 15
说明: JIT编译器自动进行循环展开优化
循环不变量外提示例:
优化前概念: 每次迭代计算array.length
优化后概念: 将不变量提取到循环外部
边界检查消除示例:
结果: 15
说明: 编译器证明不会越界,消除边界检查
性能对比:
基础循环: 15 ms
展开循环: 8 ms
性能提升: 1.88x
=== 演示完成 ===4.7 GraalCompilerDemo 执行结果
=== Graal编译器演示 ===
JVM信息:
Java版本: 17.0.x
JVM名称: OpenJDK 64-Bit Server VM
使用Graal: false
JVMCI启用: false
Graal编译器使用指南:
1. 使用Graal作为JIT编译器:
java -XX:+UnlockExperimentalVMOptions -XX:+UseJVMCICompiler ...
2. GraalVM Native Image:
native-image -cp . HelloWorld
性能测试:
计算密集型任务: 耗时 12 ms
斐波那契计算: 结果 12586269025, 耗时 0 ms
=== 演示完成 ===
提示: 安装GraalVM并使用 -XX:+UseJVMCICompiler 参数运行5. 关键JVM参数参考
5.1 JIT编译参数
| 参数 | 说明 |
|---|---|
-XX:+PrintCompilation | 打印编译日志 |
-XX:+TieredCompilation | 启用分层编译(默认开启) |
-XX:-TieredCompilation | 禁用分层编译 |
-XX:CompileThreshold=10000 | 设置编译阈值 |
-XX:ReservedCodeCacheSize=256m | 设置代码缓存大小 |
5.2 编译器优化参数
| 参数 | 说明 |
|---|---|
-XX:+DoEscapeAnalysis | 启用逃逸分析 |
-XX:+EliminateAllocations | 启用标量替换 |
-XX:+EliminateLocks | 启用同步消除 |
-XX:+UseLoopPredicate | 启用循环优化 |
-XX:+UseStringDeduplication | 启用字符串去重 |
5.3 Graal编译器参数
| 参数 | 说明 |
|---|---|
-XX:+UseJVMCICompiler | 使用Graal编译器 |
-XX:+EnableJVMCI | 启用JVMCI接口 |
-XX:+PrintGC | 打印GC日志 |
-XX:+PrintCompilation | 打印编译日志 |
6. 注意事项
- Java版本要求:代码使用Java 8+特性,Graal编译器需要Java 9+或GraalVM
- 性能测试结果:实际性能数据因硬件、JVM版本、运行环境而异
- JIT编译触发:热点代码需要达到一定调用次数才会触发编译
- 逃逸分析:需要开启
-XX:+DoEscapeAnalysis(JDK 8默认开启) - Graal编译器:需要安装GraalVM或使用
-XX:+UseJVMCICompiler参数