垃圾回收器分类与核心目标
| 垃圾回收器 | 核心目标 | 适用场景 | JDK版本支持 |
|---|---|---|---|
| CMS | 低延迟(减少STW时间) | 中小堆内存、响应敏感型应用 | JDK8及之前(JDK14废弃) |
| G1 | 平衡吞吐量与延迟(可预测停顿) | 中大堆内存(4GB~16GB) | JDK9+(默认回收器) |
| ZGC | 极低延迟(亚毫秒级STW) | 超大堆内存(TB级) | JDK11+(生产级支持JDK15+) |
CMS(Concurrent Mark-Sweep)
1. 工作阶段
- 初始标记(Initial Mark) :标记GC Roots直接关联的对象(STW,短暂停顿)。
- 并发标记(Concurrent Mark) :遍历整个对象图(与用户线程并发)。
- 重新标记(Remark) :修正并发标记期间变动的对象(STW,使用增量更新或原始快照)。
- 并发清除(Concurrent Sweep) :清理垃圾对象(与用户线程并发)。
2. 核心特点
-
优点:并发收集,减少STW时间。
-
缺点:
- 内存碎片:长期运行后需Full GC压缩堆。
- CPU敏感:并发阶段占用CPU资源,影响吞吐量。
- 浮动垃圾:并发清除期间可能产生新垃圾。
3. 调优参数
-XX:+UseConcMarkSweepGC # 启用CMS
-XX:CMSInitiatingOccupancyFraction=70 # 老年代使用率70%时触发CMS
-XX:+UseCMSCompactAtFullCollection # Full GC时压缩内存
4. 常见问题
-
并发模式失败(Concurrent Mode Failure) :
- 原因:CMS执行期间老年代空间不足。
- 解决:增大老年代空间或降低触发阈值(
CMSInitiatingOccupancyFraction)。
-
内存碎片:
- 解决:定期Full GC或切换为G1/ZGC。
G1(Garbage-First)
1. 核心设计
-
Region分区:将堆划分为多个等大小(1MB~32MB)的Region,分为Eden、Survivor、Old、Humongous(存放大对象)。
-
Mixed GC:同时回收新生代和老年代Region。
-
停顿预测模型:通过历史数据预测每次GC的停顿时间(默认目标200ms)。
把堆分成若干个Region分区的作用是实现了更细粒度的内存管理,也就是所谓的分而治之的思想,同时G1也可以实现对单个Region进行回收,从而不需要对整个堆进行扫描和回收,这样大大提高了回收效率,当然,Region的价值大小(也就是说回收所获得的内存空间大小以及回收所需时间的经验值)会被G1跟踪并记录,在允许收集时间期间,会优先回收这种价值最大的Region,所以这也是G1的名字由来(Garbage First)
2. 工作阶段
- 年轻代GC(Young GC) :回收Eden和Survivor区。
- 并发标记(Concurrent Marking) :标记老年代存活对象(类似CMS)。
- 混合回收(Mixed GC) :回收部分老年代Region(基于垃圾比例优先级)。
3. 调优参数
-XX:+UseG1GC # 启用G1
-XX:MaxGCPauseMillis=200 # 目标停顿时间(毫秒)
-XX:G1HeapRegionSize=4m # Region大小(需为2的幂)
-XX:InitiatingHeapOccupancyPercent=45 # 堆使用率45%时触发并发标记
4. 常见问题
-
大对象分配失败:
- 原因:Humongous Region不足。
- 解决:增大Region大小或减少大对象生成。
-
Mixed GC效率低:
- 解决:降低
InitiatingHeapOccupancyPercent提前触发标记。
- 解决:降低
ZGC(Z Garbage Collector)
1. 核心设计
- 染色指针(Colored Pointers) :在指针元数据中记录对象状态(可达性、重定位)。
- 读屏障(Load Barrier) :在访问对象时触发屏障,处理对象重定位。
- 无分代:全堆回收,但通过并发处理实现亚毫秒级STW。
1.1. 染色指针含义
染色指针是一种将标志位直接存储在对象指针中的技术。在 64 位系统中,指针的位数并没有被完全利用,ZGC 利用了这一点,将一些用于标记对象状态的标志位存储在指针的特定位上,就好像给指针染上了不同的 “颜色”,所以被称为染色指针。
1.1.1. 原理
在 64 位系统中,理论上可用的地址空间非常大,但实际上操作系统通常不会使用这么大的地址范围。以常见的情况为例,可能只会使用到其中 48 位来表示实际的内存地址,剩余的位就可以被 ZGC 用来存储额外的信息。 ZGC 的染色指针使用了其中的 4 位来存储 4 个标志信息,从低到高分别为:
- Marked0:用于第一次标记阶段,标记对象是否被标记过。
- Marked1:用于第二次标记阶段,和 Marked0 交替使用,避免重复初始化。
- Remapped:用于重定位阶段,标记对象是否已经被移动到新的位置。
- Finalizable:表示对象是否只能通过 finalizer 方法来访问。
2. 工作阶段
- 并发标记(Concurrent Mark) :标记存活对象。
- 并发预备重定位(Concurrent Prepare for Relocate) :确定重定位集。
- 并发重定位(Concurrent Relocate) :移动对象并更新引用。
- 引用处理(Reference Processing) :处理软/弱/虚引用。
3. 调优参数
-XX:+UseZGC # 启用ZGC
-XX:ZAllocationSpikeTolerance=5 # 内存分配尖峰容忍度(百分比)
-XX:ZCollectionInterval=120 # 强制GC间隔(秒,默认不限制)
4. 适用场景与限制
- 优势:TB级堆内存、亚毫秒级停顿(<10ms)。
- 限制:JDK15+生产级支持,Windows/macOS支持较晚。
三大回收器对比
| 维度 | CMS | G1 | ZGC |
|---|---|---|---|
| STW时间 | 中等(初始标记、重新标记) | 可控(基于预测模型) | 极低(亚毫秒级) |
| 内存占用 | 低 | 较高(Region元数据) | 高(染色指针、内存映射) |
| 吞吐量 | 中等 | 高 | 高 |
| 适用堆大小 | <4GB | 4GB~16GB | >16GB(支持TB级) |
| 内存碎片 | 严重 | 可控 | 无 |
场景选择建议
- 中小堆、低延迟:CMS(仅JDK8及之前)。
- 中大堆、平衡吞吐量与延迟:G1(JDK9+默认)。
- 超大堆、极致低延迟:ZGC(JDK15+生产环境)。
高频面试题
-
CMS为什么被废弃?
- 内存碎片问题难以解决,且G1/ZGC在吞吐量和延迟上更优。
-
ZGC如何实现几乎无STW?
- 通过染色指针和读屏障技术,将标记和重定位阶段并发执行。
-
G1的Mixed GC如何选择Region?
- 基于“垃圾优先”策略,优先回收垃圾比例高的Region。