一文吃透GC核心:GC 各类收集器与 Minor/Major/Full GC,以及四种垃圾回收算法「收集器 - 算法 - GC 类型」
在JVM内存管理中,GC(垃圾回收)是绕不开的核心话题,而新手常被“收集器、GC类型、底层算法”三者的关系绕晕——到底Serial GC和Minor GC是什么关系?标记-清除算法又被哪些收集器使用?本文将打破概念壁垒,从本质到落地,系统梳理三者的关联,帮你建立完整的GC知识体系。
一、先明确三大核心概念的本质
这三者并非并列关系,而是“底层实现(算法)→ 操作类型(GC类型)→ 具体载体(收集器)”的层层递进关系,我们先逐个拆解本质:
1. 底层垃圾回收算法(执行手段)
是GC的“底层操作逻辑”,定义了“如何识别垃圾”和“如何回收垃圾”,是所有收集器的实现基础。核心有4类(含优化变种),各有适配场景:
- 标记-清除算法:先标记不可达的垃圾对象,再直接清除。优点是实现简单、无需移动对象;缺点是产生内存碎片、回收效率低(适合存活对象多的场景)。
- 标记-复制算法:将内存划分为两块,仅使用一块,回收时复制存活对象到另一块,再清空原块。优点是无碎片、回收效率高;缺点是内存利用率低(仅50%,适合存活对象少的场景)。
- 标记-整理算法:先标记垃圾对象,再将存活对象向内存一端移动,最后清空末端垃圾。优点是无碎片、内存利用率高;缺点是移动对象开销大,STW(停止-the-世界)时间长(适合碎片敏感场景)。
- 标记-重定位算法:标记-复制的优化版,通过“染色指针”并发移动对象,无需全程STW,兼顾无碎片和低停顿(现代大内存GC的核心算法)。
2. GC类型(按回收区域划分的操作)
是对“GC操作范围”的分类,和具体收集器无关,所有收集器都需执行对应类型的GC,核心分3类(JVM规范无严格定义,以实际回收区域为准):
- Minor GC(新生代GC):仅回收新生代(Eden+Survivor区),触发条件为Eden区满,所有收集器均支持,STW时间较短(新生代对象朝生夕死,存活少)。
- Major GC(老年代GC):仅回收老年代,极少单独触发,通常与Full GC混淆,触发条件多为老年代使用率达阈值、晋升失败。
- Full GC(全堆GC):回收新生代+老年代+元空间,触发条件复杂(老年代满、显式调用System.gc()、碎片过多等),STW时间最长,需尽量避免。
3. GC收集器(算法与GC类型的载体)
是JVM提供的“GC实现组件”,本质是将底层算法与GC类型结合,根据设计目标(吞吐量/低停顿)选择适配的算法,执行对应类型的GC。主流收集器分为传统分代收集器和现代低停顿收集器两大类。
二、三者核心关联:收集器的算法与GC类型适配
收集器的核心设计逻辑的是:根据回收区域(GC类型)的特性,选择适配的底层算法——新生代必用标记-复制(存活对象少),老年代根据目标选择标记-清除/标记-整理,以下是主流收集器的完整适配关系。
1. 传统分代收集器(JDK8及之前主流)
严格遵循新生代/老年代物理分区,算法与GC类型绑定紧密,适合中小内存场景:
收集器 | 适配GC类型 | 新生代算法 | 老年代算法 | 线程模型 | 核心目标 |
|---|---|---|---|---|---|
Serial GC | Minor GC、Full GC | 标记-复制 | 标记-整理 | 单线程STW | 简单高效,适配单核/小内存(<1GB) |
Parallel GC(JDK8默认) | Minor GC、Full GC | 标记-复制 | 标记-整理 | 多线程STW | 高吞吐量,适配后台批处理服务 |
CMS GC(JDK9废弃) | Minor GC(ParNew)、Major GC | 标记-复制(ParNew执行) | 标记-清除 | 新生代多线程STW,老年代并发+少量STW | 低停顿,适配响应时间敏感服务(如电商) |
关键补充:CMS的短板的是标记-清除产生内存碎片,碎片过多时会触发Serial Old收集器的Full GC(单线程标记-整理),导致超长停顿,这也是其被废弃的核心原因。
2. 现代低停顿收集器(JDK9及之后主流)
打破物理分代限制,采用Region分区设计,算法与GC类型更灵活,适配大内存(4GB+)、低停顿需求:
收集器 | 适配GC类型(自定义命名) | 核心算法 | 线程模型 | 核心特性 |
|---|---|---|---|---|
G1 GC(JDK9默认) | Young GC(Minor)、Mixed GC(Major+Minor)、Full GC(兜底) | 标记-复制(隐含整理效果) | 并行+并发,部分STW | 优先回收垃圾多的Region,停顿可预测,无碎片 |
ZGC | 全堆回收(无分代GC类型) | 标记-重定位 | 并发移动对象,微秒级STW | 适配TB级大内存,低停顿优先 |
Shenandoah GC | 全堆回收(无分代GC类型) | 标记-重定位 | 并发移动对象,无分代设计 | 低停顿,无需依赖染色指针,兼容性好 |
关键补充:G1的Mixed GC并非严格的Full GC,仅回收部分老年代Region+新生代;ZGC/Shenandoah放弃分代,全堆用标记-重定位,彻底解决分代带来的停顿问题,适配现代大内存服务。
三、核心总结与实操选型建议
1. 三者关联一句话概括
底层算法是GC的“操作手册”,GC类型是GC的“执行范围”,收集器是“执行者”——收集器根据GC类型(范围)的特性,选用对应的算法(手册),实现不同的性能目标(吞吐量/低停顿)。
2. 收集器选型核心原则
- 小内存(<4GB)、单核/客户端程序:选Serial GC,无多线程开销。
- 中小内存、吞吐量优先(如大数据批处理):选Parallel GC,JDK8默认适配。
- 中小内存、低停顿优先(如电商接口):选G1 GC(替代废弃的CMS)。
- 大内存(4GB+)、微秒级停顿(如分布式中间件):选ZGC/Shenandoah GC。
3. 避坑要点
- 避免频繁Full GC:CMS的碎片、G1的晋升失败是主要诱因,需合理调整堆大小和晋升阈值。
- 现代GC无需执着分代:ZGC/Shenandoah无分代设计,性能更优,无需强行开启分代。
- 算法无绝对优劣:标记-复制适合新生代,标记-整理适合老年代,标记-重定位是大内存最优解,关键看适配场景。
四、拓展思考
随着内存容量的提升,GC的发展趋势是“从分代到无分代”“从STW到并发”,底层算法始终围绕“无碎片、低停顿、高利用率”三大目标优化。实际开发中,除了选型收集器,还需结合JVM参数(如-Xms/-Xmx/-XX:MaxGCPauseMillis)优化,才能让GC性能最大化。
如果需要具体收集器的JVM参数配置示例,或GC日志分析方法,可以留言交流,后续将针对性补充实操内容。