JDK 27 的性能改进

JDK 27 的性能改进

💡 原文英文,约2100词,阅读约需8分钟。
📝

内容提要

JDK 27 延续性能优化:默认启用紧凑对象头,每对象头从 12 字节降至 8 字节;G1 成为所有环境的默认垃圾回收器;HashMap、AttributedString、URL、文件输出及 AES、SHA-3 等加密代码均有提速;C2 编译器增强向量化与常量折叠。升级时建议逐项测试新默认值。

🔎

延伸解读

紧凑对象头默认启用的影响与权衡

JDK 27 将紧凑对象头设为默认,每个对象头从 12 字节降至 8 字节。JEP 519 的测量显示,在特定 SPECjbb2015 配置下堆使用降低 22%、CPU 使用降低 8%,另一配置中 G1 和 Parallel GC 的收集次数减少 15%,高度并行的 JSON 解析基准运行时降低约 10%。但收益取决于对象大小分布和对齐,大量小对象受益明显,而大原始数组主导的应用受益较小。升级时可用 -XX:-UseCompactObjectHeaders 进行 A/B 对比或作为临时回退。

G1 成为全局默认垃圾回收器的考量

JDK 27 通过 JEP 523 将 G1 设为所有环境的默认垃圾回收器,此前在小型或受限环境中可能选择 Serial GC。这主要是为了一致性,而非声称 G1 适合所有工作负载。小型容器、单处理器环境和开发机器可能观察到不同的暂停时间、CPU 使用和内存开销。Serial GC 仍可通过 -XX:+UseSerialGC 启用。配套的 JDK-8367993 推迟了 G1 并发标记初始化,减少了 VM 启动时间。

库与加密性能改进的硬件依赖性

JDK 27 对 HashMap、AttributedString、URL、文件输出及 AES、SHA-3 等加密代码进行了优化。例如,HashMap.putAll() 在源为 HashMap 时走专用路径,在 AWS Graviton 上操作时间减少 61% 至 86%;AES/ECB 在 Intel Core i9-14900HX 上吞吐量提升约 37%。但加密改进依赖硬件特性,HotSpot 根据处理器能力选择内在函数,因此应在实际部署的机器上评估这些收益。

升级测试建议:逐项验证新默认值

由于 JDK 27 引入了多个新默认值,升级时建议逐项测试。先正常测量应用在 JDK 27 上的表现,然后一次只改变一个变量(如 -XX:-UseCompactObjectHeaders 或垃圾回收器选择)以解释差异。监控指标应包括启动时间、分配速率、存活集大小、尾部延迟和 CPU 消耗,而不仅仅是峰值吞吐量。此外,最小应用在 JDK 27 上的启动时间可能与 JDK 26 相近或略慢,但内存使用最多减少 1 MB。

❓

Q&A

JDK 27 中紧凑对象头默认启用后,对象头大小有什么变化?

在典型的 64 位 HotSpot 配置上,每个对象头从 12 字节缩小到 8 字节。

JDK 27 为什么将 G1 设为所有环境的默认垃圾回收器?

这主要是为了保持一致性,而不是声称 G1 适合所有工作负载。此前 G1 已在服务器级机器上默认,但在小型或受限环境中可能仍选择 Serial GC。JEP 523 使 G1 在所有环境中成为默认,尤其影响小型容器、单处理器环境和开发机器。

JDK 27 对 HashMap 的 putAll 和构造函数做了哪些性能优化?

当源是 HashMap 或由 HashMap 支持的无修改包装器时,新增了专用路径,直接遍历源表并重用节点中存储的哈希,避免迭代器机制和重复哈希计算。在 AWS Graviton 上,操作时间减少 61% 到 86%。

JDK 27 在加密算法方面有哪些性能提升?

包括:AES/ECB 在 x86 上使用完整消息内在函数,吞吐量提升约 37%;SHA-3 增加 AVX2 内在函数并提升 AVX-512 并行度,性能提升 16% 到 39%(AVX2)和 24% 到 33%(AVX-512);ML-KEM 的数论变换乘法改进,封装和解封装提升 9% 到 17%;RISC-V 增加 AES/CTR、AES/CBC 和 GHASH 内在函数;AArch64 选择通用寄存器 SHA-3 内在函数。

JDK 27 中 C2 编译器在向量化方面有哪些增强?

SuperWord 自动向量化器现在支持子字转换,使字节和短整型的窄化或宽化循环能更多保持向量形式;移除了冗余的向量掩码转换链,识别加载/转换/存储往返;在 x86 和 AArch64 上增加了无符号最小/最大归约;重新关联广播值操作。在 NVIDIA Grace 系统上,吞吐量提升约 2.3 到 3.8 倍。

升级到 JDK 27 时,针对新的默认值应该采取什么测试策略?

建议逐项测试新默认值:先在 JDK 27 上正常测量应用,然后一次只改变一个变量(例如 -XX:-UseCompactObjectHeaders 或所选垃圾回收器)来解释任何显著差异。测量指标应包括启动时间、分配速率、活动集大小、尾部延迟和 CPU 消耗,而不仅仅是峰值吞吐量。

🏷️

标签

➡️

继续阅读