CMS(Concurrent Mark-Sweep)是 Java 中一种以低延迟为目标的垃圾回收器,主要用于老年代的垃圾回收。CMS 的核心思想是通过并发标记和并发清除来减少 STW(Stop-The-World)时间,从而降低垃圾回收对应用程序的影响。以下是 CMS 垃圾回收的详细流程:
CMS 垃圾回收的流程
1. 初始标记(Initial Mark)
- 目标:标记从 GC Roots 直接可达的对象。
- 特点:
- 这是一个 STW 阶段,会暂停所有应用线程。
- 初始标记阶段通常与年轻代垃圾回收(Minor GC)一起执行,以减少额外的停顿时间。
- 触发条件:老年代空间使用率达到一定阈值(通过
-XX:CMSInitiatingOccupancyFraction
参数设置)。
2. 并发标记(Concurrent Mark)
- 目标:遍历整个老年代,标记所有存活对象。
- 特点:
- 这是一个并发阶段,应用线程可以继续运行。
- 由于应用线程同时运行,对象图可能会发生变化,因此 CMS 使用**写屏障(Write Barrier)**来记录引用变化。
- 问题:
- 可能会产生浮动垃圾(Floating Garbage),即一些已经被标记为存活的对象实际上已经变成垃圾。
3. 并发预清理(Concurrent Preclean)
- 目标:处理在并发标记期间被修改的对象引用,减少重新标记阶段的工作量。
- 特点:
- 这是一个并发阶段,应用线程可以继续运行。
- CMS 会重新扫描被修改的对象,并处理写屏障记录的引用变化。
4. 重新标记(Remark)
- 目标:处理在并发标记和并发预清理期间遗漏的对象,确保所有存活对象都被正确标记。
- 特点:
- 这是一个 STW 阶段,会暂停所有应用线程。
- CMS 使用**增量更新(Incremental Update)**算法,重新扫描被修改的对象。
- 问题:
- 由于需要处理所有遗漏的对象,重新标记阶段可能会导致较长的停顿时间。
5. 并发清除(Concurrent Sweep)
- 目标:清除未被标记的对象(即垃圾对象)。
- 特点:
- 这是一个并发阶段,应用线程可以继续运行。
- CMS 会清理老年代中的垃圾对象,释放内存空间。
- 问题:
- 可能会产生浮动垃圾(Floating Garbage),这些浮动垃圾会在下一次垃圾回收时被清理。
6. 并发重置(Concurrent Reset)
- 目标:重置 CMS 内部的数据结构,为下一次垃圾回收做准备。
- 特点:
- 这是一个并发阶段,应用线程可以继续运行。
- CMS 会清理内部状态,准备下一次垃圾回收。
CMS 垃圾回收的总结
阶段 | 特点 | 是否 STW |
---|---|---|
初始标记 | 标记 GC Roots 直接可达的对象,通常与年轻代垃圾回收一起执行 | 是 |
并发标记 | 遍历老年代,标记所有存活对象 | 否 |
并发预清理 | 处理并发标记期间被修改的对象引用 | 否 |
重新标记 | 处理遗漏对象,确保所有存活对象都被正确标记 | 是 |
并发清除 | 清除未被标记的对象,释放内存空间 | 否 |
并发重置 | 重置 CMS 内部数据结构,为下一次垃圾回收做准备 | 否 |
CMS 垃圾回收的特点
- 低延迟:通过并发标记和并发清除,减少 STW 时间。
- 浮动垃圾:由于并发执行,可能会产生浮动垃圾,这些浮动垃圾会在下一次垃圾回收时被清理。
- 内存碎片:CMS 使用标记-清除算法,不会压缩堆内存,可能会导致内存碎片。
- 触发条件:老年代空间使用率达到一定阈值时触发。
CMS 的适用场景
- 低延迟应用:如实时系统、交互式应用等,对停顿时间敏感的场景。
- 中等规模堆内存:CMS 适用于堆内存大小在几 GB 到几十 GB 之间的应用。
CMS 的局限性
- 内存碎片:由于 CMS 不会压缩堆内存,长时间运行后可能会导致内存碎片,从而触发 Full GC。
- 浮动垃圾:并发执行可能导致浮动垃圾,增加内存占用。
- CPU 资源消耗:并发标记和并发清除会占用一定的 CPU 资源,可能影响应用程序的性能。
总结
CMS 垃圾回收器通过并发标记和并发清除来减少 STW 时间,适用于对低延迟要求较高的应用场景。然而,它也存在内存碎片和浮动垃圾等问题,需要根据具体应用场景进行调优和选择。随着 G1 和 ZGC 等新一代垃圾回收器的发展,CMS 已逐渐被淘汰,但在某些特定场景下仍然有其应用价值。
THE END
暂无评论内容