开发者社区 > 博文 > JDK垃圾回收策略演进史:从Serial到ZGC的爱恨情仇
分享
  • 打开微信扫码分享

  • 点击前往QQ分享

  • 点击前往微博分享

  • 点击复制链接

JDK垃圾回收策略演进史:从Serial到ZGC的爱恨情仇

  • jd****
  • 2025-11-03
  • IP归属:北京
  • 122浏览

    "垃圾回收就像家务活,你不做它就堆积如山,做得太频繁又影响正事。"

                                                                                                          —— 某位被GC折磨的程序员

    前言:垃圾回收器的江湖恩怨

    在Java的世界里,垃圾回收器(Garbage Collector,简称GC)就像是幕后的清洁工,默默地清理着程序运行时产生的"垃圾"。从JDK 1.0到如今的JDK 21,这些清洁工们经历了怎样的进化历程?让我们一起来看看这场持续了近30年的"清洁革命"。

    第一章:Serial GC - 单打独斗的老兵

    出生年月:JDK 1.0时代

    性格特点:专一、简单、但有点慢

    适用场景:单核CPU或小内存应用

    Serial GC就像那个年代的老师傅,一个人包揽所有活儿。它的工作方式非常简单粗暴:

    应用线程:我要分配内存!

    Serial GC:等等,让我先停下所有工作,清理一下垃圾...

    应用线程:😴(被迫休息)

    Serial GC:好了,你可以继续了

    应用线程:终于...(已经过去了好几秒)

    优点:

    • 简单可靠,不会出幺蛾子

    • 内存占用小,适合嵌入式设备

    • 单线程操作,不存在线程同步问题

    缺点:

    • STW(Stop The World)时间长,用户体验差

    • 无法利用多核CPU优势


    第二章:Parallel GC - 多线程的力量

    出生年月:JDK 1.4引入,JDK 8成为默认选择

    性格特点:团队合作,追求高吞吐量

    默认使用版本:JDK 7、JDK 8

    到了多核时代,Oracle意识到一个人干活太慢了,于是派出了一个团队——Parallel GC。

    应用线程:我需要清理垃圾!

    Parallel GC Team:收到!小A你清理新生代,小B你清理老年代,小C你整理内存碎片

    应用线程:😴(还是要等,但时间短了很多)

    Parallel GC Team:搞定!比Serial快3倍!

    JDK 8的选择逻辑:

    • 如果是服务器级别的机器(多核CPU + 大内存),默认使用Parallel GC

    • 如果是客户端机器,可能使用Serial GC

    优点:

    • 充分利用多核CPU

    • 高吞吐量,适合批处理应用

    • 成熟稳定,经过长期验证

    缺点:

    • STW时间仍然不可控

    • 延迟敏感的应用表现不佳

    第三章:CMS GC - 追求低延迟的艺术家

    出生年月:JDK 1.4引入,JDK 6成熟

    性格特点:追求完美,但有强迫症

    特殊技能:并发标记清除

    CMS(Concurrent Mark Sweep)就像一个有洁癖的艺术家,它不能忍受长时间的停顿:

    应用线程:我在运行业务逻辑...

    CMS GC:我悄悄地标记一下垃圾对象(并发进行)

    应用线程:我继续运行...(几乎感觉不到GC的存在)

    CMS GC:好了,我快速清理一下(短暂停顿)

    应用线程:咦?刚才停了一下吗?

    优点:

    • 大部分工作与应用线程并发进行

    • 停顿时间短,用户体验好

    • 适合响应时间敏感的应用

    缺点:

    • 不整理内存碎片,可能导致内存碎片化

    • 并发执行会占用CPU资源

    • 在JDK 9中被标记为废弃,JDK 14中完全移除

    第四章:G1 GC - 新时代的全能选手

    出生年月:JDK 7引入,JDK 9成为默认选择

    性格特点:平衡大师,追求可预测性

    默认使用版本:JDK 9-21(至今)

    G1(Garbage First)就像一个经验丰富的项目经理,它把内存划分成许多小区域(Region),然后优先处理垃圾最多的区域:

    G1 GC:让我看看...这个Region垃圾最多,先处理它

    应用线程:我设定了停顿时间目标是100ms

    G1 GC:收到!我会在100ms内完成,超时就停手

    应用线程:真的吗?

    G1 GC:我尽力而为!(90%的情况下都能做到)

    为什么从JDK 9开始成为默认:

    • 可以设置停顿时间目标(-XX:MaxGCPauseMillis)

    • 适用于大堆内存(>4GB)

    • 在吞吐量和延迟之间取得很好的平衡

    优点:

    • 可预测的停顿时间

    • 适合大内存应用

    • 自动调优能力强

    • 并发标记和回收

    缺点:

    • 内存占用稍高(大约10-20%的额外开销)

    • 小堆内存下性能不如Parallel GC

    第五章:ZGC - 未来的超级英雄

    出生年月:JDK 11引入(实验性),JDK 15正式发布

    性格特点:极速,几乎感觉不到停顿

    特殊能力:超低延迟(<10ms)

    ZGC就像超级英雄,它的目标是让GC停顿时间永远不超过10毫秒,无论堆有多大:

    应用线程:我有16TB的堆内存...

    ZGC:没问题!

    应用线程:停顿时间能控制在10ms以内吗?

    ZGC:小case!我有彩色指针技术!

    应用线程:什么是彩色指针?

    ZGC:这个说来话长...(开始炫技)

    技术特点:

    • 使用彩色指针(Colored Pointers)技术

    • 并发收集,几乎不停顿应用

    • 支持TB级别的堆内存

    第六章:各版本默认GC策略总结

    JDK版本对照表:

    JDK 1.0-6:默认Serial GC

    特点:单线程,简单

    适用场景:小应用,单核CPU

    JDK 7-8:默认Parallel GC

    特点:多线程,高吞吐

    适用场景:批处理,多核服务器

    JDK 9-21:默认G1 GC

    特点:平衡延迟和吞吐

    适用场景:大部分现代应用

    JDK选择GC的智能逻辑

    JDK在选择默认GC时会考虑以下因素:

    1. 机器配置:

      • 单核 → Serial GC

      • 多核 + 小内存 → Parallel GC

      • 多核 + 大内存 → G1 GC

    2. 应用类型:

      • 批处理 → Parallel GC

      • 交互式应用 → G1 GC

      • 超低延迟要求 → ZGC

    第七章:如何选择合适的GC

    选择指南

    选择GC的决策流程:

    开始选择GC → 判断堆内存大小 → 如果小于4GB,判断是否对延迟敏感 → 如果敏感选择G1 GC,否则选择Parallel GC

    如果大于4GB → 判断是否有极低延迟要求 → 如果有选择ZGC,否则选择G1 GC

    实际配置建议

    小型应用(堆内存 < 2GB):

    使用Parallel GC(JDK 8默认):

    -XX:+UseParallelGC

    或者使用G1 GC:

    -XX:+UseG1GC -XX:MaxGCPauseMillis=200

    中大型应用(堆内存 2GB-32GB):

    使用G1 GC(JDK 9+默认):

    -XX:+UseG1GC

    -XX:MaxGCPauseMillis=100

    -XX:G1HeapRegionSize=16m

    超大型应用(堆内存 > 32GB):

    使用ZGC(JDK 11+):

    -XX:+UseZGC

    -XX:+UnlockExperimentalVMOptions  # JDK 11-14需要

    第八章:GC调优的江湖秘籍

    秘籍一:监控先行

    开启GC日志:

    -Xloggc:gc.log

    -XX:+PrintGCDetails

    -XX:+PrintGCTimeStamps

    秘籍二:渐进调优

    1. 先观察:收集至少一周的GC数据

    2. 找瓶颈:识别是吞吐量问题还是延迟问题

    3. 小步调整:一次只调一个参数

    4. 验证效果:观察至少24小时

    秘籍三:常见参数组合

    追求吞吐量(Parallel GC):

    -XX:+UseParallelGC

    -XX:ParallelGCThreads=8

    -XX:MaxGCPauseMillis=500

    追求低延迟(G1 GC):

    -XX:+UseG1GC

    -XX:MaxGCPauseMillis=50

    -XX:G1NewSizePercent=30

    -XX:G1MaxNewSizePercent=40

    第九章:未来展望

    即将到来的新特性

    1. 分代ZGC:JDK 21引入,结合分代收集和超低延迟

    2. Shenandoah GC:RedHat贡献的低延迟收集器

    3. 更智能的自适应调优:AI辅助的GC参数优化

    发展趋势

    • 更低的延迟:从秒级到毫秒级,再到微秒级

    • 更高的吞吐量:充分利用现代硬件特性

    • 更简单的配置:自适应调优,减少人工干预

    • 更好的可观测性:实时监控和诊断工具

    结语:GC的哲学思考

    垃圾回收器的演进史,其实就是一部计算机科学追求性能与易用性平衡的历史。从Serial的简单粗暴,到Parallel的并行处理,再到G1的智能平衡,最后到ZGC的极致追求,每一步都体现了工程师们对完美的不懈追求。

    正如一位资深Java工程师说过:"选择GC就像选择人生伴侣,没有完美的,只有最适合的。"

    最后的建议

    1. 不要过早优化:先让程序跑起来,再考虑GC调优

    2. 测量驱动:用数据说话,不要凭感觉调优

    3. 保持学习:GC技术在不断发展,要跟上时代步伐

    4. 理解业务:GC调优要结合具体的业务场景

    记住:最好的GC就是你感觉不到它存在的GC。

    "在Java的世界里,我们都是垃圾制造者,而GC是我们最好的朋友。"

    参考资料

    • Oracle JDK Documentation

    • OpenJDK GC Wiki

    • 《深入理解Java虚拟机》- 周志明

    • 《Java性能权威指南》- Scott Oaks

    文章数
    1
    阅读量
    122

    作者其他文章