JDK 17 的 G1 垃圾回收器(Garbage-First)相比 JDK 8 的 G1 有诸多重要改进,主要体现在性能优化、功能增强、默认配置调整等方面,这些改进让 G1 在大堆场景、低延迟需求下表现更优。以下是核心区别:
1. Full GC 从串行变为并行
- JDK 8 的 G1 :Full GC(全局垃圾回收)是串行执行的,即单线程处理整个堆的回收,在大堆(如几十 GB)场景下会导致极长的停顿时间(可能秒级甚至分钟级),严重影响服务可用性。
- JDK 17 的 G1 :从 JDK 10 开始引入并行 Full GC,并在后续版本(包括 17)中持续优化。Full GC 阶段会使用多个线程并行处理,大幅缩短大堆场景下的停顿时间(通常可减少 50% 以上)。
2. 混合收集(Mixed GC)策略优化
- JDK 8 的 G1:混合收集的触发和范围选择策略较简单,可能导致频繁的混合收集,或对"存活对象较多的 Region"回收不彻底,浪费 CPU 资源。
- JDK 17 的 G1 :
- 引入"快速混合收集(Quick Mixed GC)"(JDK 12+),通过更智能的 Region 筛选算法,减少不必要的混合收集次数,优先回收"垃圾比例高"的 Region,提升效率。
- 优化了混合收集的终止条件,避免过度收集导致的性能损耗。
3. 停顿时间控制更精准
- JDK 8 的 G1 :在高负载或复杂堆结构下,实际停顿时间可能显著超过用户设置的目标(
-XX:MaxGCPauseMillis
),尤其是大堆场景。 - JDK 17 的 G1 :
- 改进了"停顿预测模型",能更准确地估算回收所需时间,减少超出目标停顿的情况。
- 优化了 Young GC 和 Mixed GC 中"根扫描""对象复制"等阶段的并行效率,进一步压缩停顿时间。
4. 内存管理优化
- Region 大小动态调整:JDK 8 中 G1 的 Region 大小(默认 1MB~32MB)是启动时固定的,无法适应堆内存的动态变化。JDK 17 中支持更灵活的 Region 大小调整策略(尤其是大堆场景),减少内存碎片。
- 记忆集(Remembered Set)优化:记忆集是 G1 跟踪跨 Region 引用的核心数据结构,JDK 17 减少了记忆集的维护开销(如优化卡片表扫描效率),降低了 CPU 占用。
- 大对象处理:JDK 8 中大对象(超过 Region 一半大小)直接分配到"大对象区域(Humongous Region)",可能导致频繁的 Full GC;JDK 17 优化了大对象的分配和回收逻辑,减少对 Full GC 的依赖。
5. 默认配置更合理
- JDK 8:G1 并非默认垃圾回收器(默认是 Parallel GC),且部分参数(如混合收集的阈值、线程数)默认值较保守,需要手动调优才能发挥最佳性能。
- JDK 17:G1 是默认垃圾回收器,且默认参数经过大幅优化(如根据 CPU 核心数自动调整 GC 线程数、更合理的混合收集阈值),大部分场景下无需手动调优即可获得较好性能。
6. 其他重要改进
- 字符串去重(String Deduplication)优化:JDK 8 中虽支持字符串去重,但实现较简单,可能导致额外的性能开销;JDK 17 优化了去重的触发时机和算法,减少对业务线程的影响。
- 元空间(Metaspace)回收整合:JDK 17 中 G1 对元空间的回收更主动,避免因元空间溢出导致的 Full GC。
- NUMA 感知优化:在多 CPU 节点(NUMA)系统中,JDK 17 的 G1 能更智能地分配内存,减少跨节点内存访问的开销。
总结
JDK 17 的 G1 在性能、稳定性、易用性上全面超越 JDK 8 的 G1,尤其在大堆(>10GB)、低延迟需求的服务(如分布式系统、大型应用服务器)中优势明显。如果从 JDK 8 升级到 JDK 17,无需修改代码即可享受 G1 的这些优化,对于对延迟敏感的业务,收益会更显著。