JVM-垃圾回收器
JVM——垃圾回收器
1. 垃圾回收器分类
分类标准:串行/并行、并发/独占、压缩式/非压缩式、年轻代/老年代
2. 回收器评价标准
- 吞吐量:$\frac{t_{运行用户代码}}{t_{运行用户代码} + t_{垃圾回收}}$,即尽可能让单位时间内的STW时间最短
- 暂停时间:尽可能让单次STW时间最短
3. Serial回收器

串行;年轻代为Serial(标记-复制算法),老年代为Serial Old(标记-整理算法)
4. ParNew回收器

并行;只能用于年轻代(标记-复制算法),老年代仍为Serial-Old
5. Parallel Scavenge回收器

并行;关注吞吐量;年轻代为Parallel Scavenge(标记-复制算法),老年代为Parallel Old(标记-整理算法)
6. CMS回收器(Concurrent-Mark-Sweep)

并发;只能用于老年代,但无法与Parallel Scavenge一起使用
CMS回收器收集流程
- 初始标记:只标记出与GCRoots直接关联的对象,会发生STW但时间短
- 并发标记:从上面得到的与GCRoots直接关联的对象开始遍历标记,可与工作线程并发执行,无需STW
- 重新标记:修正并发标记过程中,由于用户程序继续运行导致标记产生变动的一部分对象的标记记录,会产生STW但时间也不长
- 并发清除:删除标记阶段判断死亡的对象,由于没移动对象(标记-清除),故可以与用户线程并发执行
- 优点:并发;低延迟
- 缺点:
- 由于采用的是标记-清除算法,会产生内存碎片;
- 会产生**“浮动垃圾”**:由于并发清除阶段是与工作线程并发执行的,这期间产生的垃圾要等到下次gc次才能清除
CMS回收器的兜底策略
CMS 最大的弱点在于它使用的是标记-清除(Mark-Sweep)算法,这会产生大量的内存碎片。
- 触发场景:
- 并发失败(Concurrent Mode Failure): 当 CMS 还在进行并发回收时,老年代的剩余空间已经不足以支撑新对象的分配(或者是从年轻代晋升过来的对象)。
- 晋升失败(Promotion Failed): 虽然老年代总空闲空间够,但由于碎片化太严重,找不到一块连续的空间来存放晋升的大对象。
- 兜底操作:
- Serial Old GC: CMS 会立即停止所有工作,切换到单线程的 Serial Old 收集器。
- 全堆压缩: 这是一个极重的操作,它会进行全堆扫描并进行内存压缩(Compaction)以消除碎片。
- 后果: 产生一个非常漫长的 STW 停顿,在几十 GB 的堆内存上,这可能会导致应用“假死”数秒甚至数分钟。
7. G1回收器(Garbage First)

G1回收器将堆内存分割为许多个小区域region,G1跟踪各个region里垃圾堆积价值大小(回收获得空间大小 以及 回收所需时间的经验值),在后台维护一个优先列表,每次根据允许时间,优先回收价值最大的region
G1回收器收集流程:
- 初始标记
- 并发标记
- 重新标记
- 筛选回收:制定回收计划,选择多个region作为回收集,把回收集中存活对象复制到空的region中,再清理旧region中的全部空间,需要STW
G1 的兜底策略
G1 采用的是分代/分区(Region)算法,虽然它比 CMS 更智能,但依然有极限。
- 触发场景:
- 转移失败(Evacuation Failure): G1 在将存活对象从一个 Region 复制到另一个 Region(To-Space)时,发现没有可用的空闲 Region 了。
- 并发模式失败(Concurrent Mode Failure): 在并发标记完成前,堆内存就已经被填满。
- 巨型对象分配失败: 当大对象请求分配,但连续的空闲 Region 数量不足时。
- 兜底操作:
- Full GC: 触发一次全堆范围的 STW 回收。
- 版本差异:
- JDK 8 及以前: G1 的 Full GC 是单线程的,性能非常差。
- JDK 10 及以后: G1 的 Full GC 得到了优化,改为并行(Parallel Full GC),利用多核 CPU 加快清理速度。
- 后果: 虽然在现代 JDK 中由于是多线程并行清理,速度比 CMS 的单线程兜底快不少,但依然属于“重度卡顿”。
8. CMS G1垃圾回收器的三色标记是什么?
三色标记是用于垃圾回收的标记算法,CMS 和 G1 垃圾回收器都有采用。它将对象分为三种颜色:
白色:初始状态,代表尚未被垃圾回收器访问的对象。标记结束仍为白色的对象,意味着未被程序引用,会被当作垃圾回收。
灰色:表示对象已被访问,但它引用的其他对象还没全被访问,处于“中间状态”。
黑色:对象及其引用的所有对象都已被访问过。黑色对象在本轮标记中不会被回收。
三色标记能在并发标记时,和用户线程并发执行,提高效率,但可能产生浮动垃圾和对象消失问题。
JVM-垃圾回收器
http://example.com/2025/05/16/JVM-垃圾回收器/