JRE 23在CPU密集无堆场景下性能提升的原因探究
测试代码
以下是用于性能测试的纯CPU密集型代码,仅针对double类型执行大量计算,单线程且不使用堆内存:
public class PerfTestSampleJ { private static final int MEASURE_COUNT = 5; private static final int ITERATIONS = 100_000_000; public static void main(String[] args) { var minTime = Long.MAX_VALUE; for (int i = 1; i <= MEASURE_COUNT; i++) { long start = System.nanoTime(); double pi = calculatePi(ITERATIONS); long time = System.nanoTime() - start; System.out.printf("Iteration %2d took %8.3f ms%n", i, time / 1e6); if (time < minTime) { minTime = time; } if (Math.abs(pi - Math.PI) > 1e-14) throw new AssertionError(pi + " (" + (pi - Math.PI) + ")"); } System.out.printf("Minimum time taken: %8.3f ms%n", minTime / 1e6); } private static double calculatePi(int iterations) { double pi = 0.0; double numerator = 4.0; for (int i = 1; i <= iterations; i++) { double n = i * 2.0; double denominator = n * (n + 1) * (n + 2); pi += numerator / denominator; numerator = -numerator; } return 3 + pi; } }
测试结果
使用同一编译后的类文件,对比JRE 21与JRE 23的运行结果:
# JRE 21.0.5运行结果 /usr/lib/jvm/jdk-21.0.5-oracle-x64/bin/java PerfTestSampleJ Iteration 1 took 801.058 ms Iteration 2 took 798.392 ms Iteration 3 took 414.688 ms Iteration 4 took 413.959 ms Iteration 5 took 416.867 ms Minimum time taken: 413.959 ms # JRE 23.0.1运行结果 /usr/lib/jvm/jdk-23.0.1-oracle-x64/bin/java PerfTestSampleJ Iteration 1 took 193.654 ms Iteration 2 took 186.790 ms Iteration 3 took 102.963 ms Iteration 4 took 103.226 ms Iteration 5 took 102.869 ms Minimum time taken: 102.869 ms
测试背景
每次运行的前2次迭代为预热阶段,从第3次迭代起性能达到最优。对比可知JRE 23的运行速度远快于JRE 21,但查阅JRE 23发布说明,仅发现垃圾收集器相关性能优化,而本测试未使用堆内存,该优化与此无关。
补充测试环境:基于Ubuntu Linux x64平台的i7处理器,使用Temurin版本也得到相同结果;在Windows x64平台测试Oracle JRE 22与23时,也呈现类似性能差异,说明性能提升发生在JRE 22到23的版本迭代中。
性能提升的可能原因
针对这个纯浮点计算场景,JRE 23中以下几类改动最可能导致性能提升:
JIT编译器的浮点优化增强
HotSpot的C2编译器在JRE 23中做了多项针对浮点计算的优化:- 循环自动向量化优化:编译器对
calculatePi中的循环进行了更高效的向量化处理,将批量double运算打包到SIMD指令(如AVX-2/AVX-512)中执行,大幅提升计算吞吐量,这是此类场景性能提升的核心原因。 - 冗余计算消除与常量折叠:对循环内的
n = i * 2.0、n + 1等表达式做了更彻底的优化,减少不必要的浮点操作步骤。 - 寄存器分配优化:改进了浮点寄存器的分配策略,减少循环内的寄存器溢出和重新加载操作,降低内存访问开销。
- 循环自动向量化优化:编译器对
底层浮点指令生成优化
JRE 23针对x86/AMD64平台调整了部分浮点运算的指令生成逻辑,比如优化除法、加法的指令序列,更好匹配现代CPU的微架构特性,提升单指令执行效率。JIT编译触发策略调整
JRE 23可能微调了C2编译器的编译触发阈值,让calculatePi方法更快进入完全优化状态,但从测试结果看,第3次迭代已稳定,该因素影响相对较小。
这类优化通常不会在发布说明中单独详细列出,而是包含在"HotSpot编译器改进"这类概括性条目下。可以通过添加-XX:+PrintCompilation参数观察JIT编译细节,或使用-XX:+PrintAssembly查看生成的机器码,确认是否有向量化指令生成。
内容的提问来源于stack exchange,提问作者k314159

