JDK 27 G1/Parallel/Serial GC 变更

Hacker News Top 产品

摘要

JDK 27 引入了对 HotSpot 的 stop-the-world 垃圾收集器的显著更改,最重要的是 JEP 523 使 G1 在所有环境中成为默认 GC,同时还包含各种改进、重构和错误修复。

暂无内容
查看原文
查看缓存全文

缓存时间: 2026/08/13 21:22

# JDK 27 中 G1/Parallel/Serial GC 的变更 来源:https://tschatzl.github.io/2026/08/10/jdk27-g1-serial-parallel-gc-changes.html OpenJDK 28 即将发布,我想是时候再次讨论 OpenJDK HotSpot VM 中 Stop-The-World 收集器的一些有趣变更了。JDK 27 的 GC 子组件的已解决/已关闭变更完整列表请见这里(https://bugs.openjdk.org/issues/?jql=project%20%3D%20JDK%20AND%20status%20%3D%20Resolved%20AND%20fixVersion%20%3D%20%2227%22%20AND%20component%20%3D%20hotspot%20AND%20Subcomponent%20%3D%20gc%20ORDER%20BY%20summary%20ASC%2C%20status%20DESC),总共约 350 项变更。这个原始数量与上个版本相当;与当时类似,这些数字可能略有虚高,因为 GC 代码中出现了相当数量的重构和清理。其中一个特定领域是替换我们用来指示跨线程共享变量的惯用写法,从使用 `volatile` 和相应的 `AtomicAccess` 方法,改为使用 JDK-8367013(https://bugs.openjdk.org/browse/JDK-8367013)引入的 `Atomic`,以使其使用更加明确。其他值得注意的重构包括 G1 状态机清理(包括一些非常非常古老(https://bugs.openjdk.org/browse/JDK-8080226)的清理)以及其他代码改进。这些约占变更的一半。另有约 35% 的变更涉及错误修复以及一般正确性和健壮性改进。其余部分则涉及 HotSpot STW 收集器的新行为或实质性修订行为——这也是本文接下来要深入探讨的部分 :) 在这些变更中,还包含了 JEP 401:Value Objects(Preview)(https://openjdk.org/jeps/401)的基础设施工作,例如调整对象迭代器以及对值对象的急切回收。 本版本中最具影响力的变更可能是 JEP 523:Make G1 the Default Garbage Collector in All Environments(https://openjdk.org/jeps/523)。现在,如果没有在命令行上显式指定任何垃圾收集算法,G1 就是默认收集器。没有任何例外,默认情况下任何场景都不会使用 Serial GC(也就是说,除非你的 OpenJDK 发行版未包含 G1)。我们认为 G1 非常适合作为默认收集器,而根据晦涩的环境条件选择其他收集器,与其说是优势,不如说是负担。在过去的几个版本中,G1 的吞吐量、内存占用和延迟表现逐步逼近 Serial GC,所以我们觉得是时候切换默认选择了。如果你观察到显著差异,仍然可以使用 `-XX:+UseSerialGC` 选项选择原始的、未修改的 Serial GC。显然在某些情况下,对于你的应用特征而言 Serial GC 是更好的选择——G1 并非在所有地方都是最好的,但我们认为它绝对是最适合起步的。 除了这项变更之外,还有其他几项: - G1 不再根据(任意的)`-XX:MinHeapFreeRatio` 和 `-XX:MaxHeapFreeRatio` 百分比在 Full GC 后调整堆大小,也就是说,它们的默认值已经被设置为不会影响常规的、基于其他启发式算法的堆大小调整(例如垃圾收集器 CPU 使用率相对于应用程序 CPU 使用率的比例)。JDK-8238686(https://bugs.openjdk.org/browse/JDK-8238686)将它们的默认值分别从 `40%` 和 `70%` 改为 `0%` 和 `100%`。原有的默认值会导致这个启发式算法与其他基于 CPU 使用率的启发式算法相互冲突,造成不必要的 Java 堆大小调整;当一次 Full GC 收缩堆后,其他启发式算法几乎立即撤销这些调整,从而引发性能问题。除此之外,这些标志的功能保持不变。 - 对并发标记的自适应启动进行了改进,使其更能抵抗不利条件,此前这些条件会导致不必要且持续的并发工作(JDK-8379846(https://bugs.openjdk.org/browse/JDK-8379846)、JDK-8381006(https://bugs.openjdk.org/browse/JDK-8381006))。 - 此前,实际上可以被回收的巨型对象(humongous objects)会被弱引用(例如 `java.lang.ref.Reference` 实例)无意中保持在存活状态,已通过 JDK-8378331(https://bugs.openjdk.org/browse/JDK-8378331)和 JDK-8378336(https://bugs.openjdk.org/browse/JDK-8378336)修复。 - 一些小规模的可观察变化包括:G1 Cleanup 暂停不再更新 `MemoryPoolMXBean.getCollectionUsage()`,因为它们不会改变 Java 堆(JDK-8386332(https://bugs.openjdk.org/browse/JDK-8386332))。JDK-8373894(https://bugs.openjdk.org/browse/JDK-8373894):此前,无法找到足够空间进行复制的垃圾回收不会计入垃圾收集器 CPU 使用率。将它们计入可以改善堆大小调整决策。 ## Parallel GC Parallel GC 有一些值得注意的错误修复,可能会提升性能: - 自适应晋升阈值(adaptive tenuring threshold)决定了对象可以在年轻代中经历多少次年轻代回收。此前,该阈值往往只会升高,极少降低。这意味着持续偏高的阈值可能会让较老的对象占据大量幸存者空间,从而在幸存者空间填满时迫使较年轻的对象过早晋升。通过 JDK-8380590(https://bugs.openjdk.org/browse/JDK-8380590),该阈值也可以降低,从而更快地晋升长生命周期对象,并将可能在短时间内消亡的较年轻对象保留在年轻代中。 - Parallel GC 现在能够在重复的大型分配导致数千次 Full GC 时正确扩展 Java 堆,即使有足够的剩余空间,此前的 Java 堆也不会增长(JDK-8377561(https://bugs.openjdk.org/browse/JDK-8377561))。 ## Serial GC Serial GC 没有特别值得注意的变更——除了在某些场景下不再是默认收集器。 ## 所有收集器 所有收集器都有一些有趣的变更: - TLAB 大小调整现在能更好地处理创建大量短生命周期、分配量较低的线程的应用。这避免了 TLAB 过度分配导致大量浪费,进而增加回收次数(JDK-8381834(https://bugs.openjdk.org/browse/JDK-8381834))。 - JDK-8372348(https://bugs.openjdk.org/browse/JDK-8372348)改进了字符串去重(string deduplication)的日志和 JFR 事件。日志新增了“new unknown”字符串,并提供更有意义的聚合字节数统计。 ## 下一步 我们的重点仍然是自动堆大小调整(Automatic Heap Sizing),改进内存管理各个方面的控制,使 G1 能够更智能地响应外部条件和用户意图。 ## 感谢…… ……一如既往地感谢所有为又一个 JDK 版本做出贡献的人。最后,随着一些重大重构(`Atomic`)的完成,我们有了更多时间来处理其他事项。期待在下一个版本——也许更大的版本——中与大家相见 :) *Thomas*

相似文章

JDK 27 已发布

Lobsters Hottest

JDK 27 作为 Java SE 平台版本 27 的参考实现已发布,包含的更新包括将 G1 设为默认垃圾回收器和 TLS 1.3 的后量子混合密钥交换。

Java 27 发布

Hacker News Top

Java 27 (JDK 27) 现已正式发布,主要增强功能包括将G1设为默认垃圾回收器、为TLS 1.3提供后量子混合密钥交换以及多种预览功能。

为什么 Arrays.fill 在 G1GC 上慢了 265 倍?

Hacker News Top

本文探讨了为什么 Arrays.fill 在 G1GC 上比在 ParallelGC 上慢了 265 倍,通过详细的性能分析和汇编代码分析,将问题追溯到 JIT 生成的代码和内存屏障。

观察 Go 的新垃圾回收器在堆中的移动

Lobsters Hottest

Go 1.26 将 Green Tea 设为默认垃圾回收器,提升了缓存友好性。本文通过 Go 和 C# 可视化堆分配,并讨论了非移动回收器和稀疏页面带来的挑战。