游乐游手机版
首页/编程语言/文章详情

CMS垃圾收集器详解初始标记并发标记重新标记与并发清除阶段分析

时间:2026-05-07 07:15
CMS垃圾收集器以低延迟为目标,其四个阶段中仅初始标记和重新标记需要暂停所有用户线程。初始标记快速标记直接关联对象,重新标记修正并发标记期间变动的引用,两者停顿时间极短。而并发标记和并发清除阶段则与用户线程并行执行,避免了长时间中断。

CMS垃圾收集器详解:初始标记、并发标记、重新标记、并发清除四个阶段中哪些需要Stop The World

CMS 垃圾收集器:详解初始标记、并发标记、重新标记、并发清除四个阶段中哪些需要 Stop The World

在探讨CMS垃圾收集器时,一个关键问题常常被提出:它究竟在哪些阶段会引发“世界暂停”?明确来说,在其标准工作流程的四个阶段中,仅有初始标记和重新标记这两个环节需要触发Stop The World(STW)。这一设计精准地体现了CMS以“最小化延迟”为核心的设计哲学。

初始标记阶段为何必须STW

初始标记阶段可以视作一次高效的“闪电扫描”。其核心任务非常明确:仅标记那些与GC Roots直接相连的第一层对象。具体包括:

  • 虚拟机栈(局部变量表)中直接引用的对象
  • 本地方法栈中JNI引用的Java对象
  • 方法区中静态属性引用的类对象
  • 方法区中常量池引用的字符串等对象

由于只需进行一层快速扫描,此阶段的停顿时间极短,通常可控制在毫秒级。但为何必须暂停所有用户线程?根本原因在于确保标记基准的准确性——必须冻结应用状态,获取一个瞬间的、一致的“内存根集快照”。若用户线程仍在运行,根对象集合将处于动态变化中,标记工作便失去了可靠的基础。

并发标记阶段为何无需STW

初始标记完成后,CMS即进入最耗时的并发标记阶段。在此阶段,垃圾收集线程将从已标记的根对象出发,递归遍历整个对象引用链,逐步标记出所有存活的、可达的对象。

此过程的核心优势在于与用户线程并发执行。这意味着应用程序可以持续提供服务,不会因垃圾回收而中断。当然,并发标记在避免停顿的同时,也带来了较长的执行时间,并且会与用户线程竞争CPU计算资源,对系统吞吐量有一定影响。

重新标记阶段为何必须STW

由于并发标记阶段用户线程仍在运行,新的问题随之产生:在漫长的标记过程中,用户线程可能创建了新对象或改变了原有引用关系,导致部分对象出现“漏标”(本应存活却未标记)或“误标”(本应回收却被标记)的情况。

重新标记阶段正是为解决此问题而设。它负责进行最终修正,处理在并发标记期间发生变动的对象引用。此阶段必须再次暂停所有用户线程,以确保能基于一个稳定的内存状态完成最终标记。虽然其耗时略长于初始标记,但相比完整的并发标记,仍是一次非常短暂的强制性暂停。

并发清除阶段为何无需STW

当所有标记工作完成后,便进入最后的清理阶段。在并发清除环节,收集器将依据最终的标记结果,直接回收那些被判定为死亡的对象所占用的内存空间。由于CMS采用经典的“标记-清除”算法,无需移动存活对象,因此整个清理过程可以安全地与用户线程并发进行,不会引发全局性停顿。

总结而言,CMS的设计逻辑清晰而高效:将最耗时的标记与清除任务尽可能置于并发阶段完成,仅保留两次不可避免的、极其短暂的轻量级暂停。这正是它被誉为“低延迟收集器”的核心机制。当然,这种设计也带来了内存碎片、并发模式失败等后续问题,需要在具体应用场景中综合权衡。

来源:https://www.php.cn/faq/2423204.html
上一篇Java只读缓冲区创建指南ByteBufferasReadOnlyBuffer方法详解与数据保护实践 下一篇Java子线程崩溃全局捕获与处理指南ThreadsetUncaughtExceptionHandler方法详解
本站内容用于信息整理与展示,如有侵权或内容问题请及时联系处理。

相关推荐

补充同频道和同主题内容,方便继续浏览更多相关内容。

同类最新

继续查看同栏目最近更新的文章。

更多
列表遍历时动态判断阈值并返回相应文本
编程语言 · 2026-07-08

列表遍历时动态判断阈值并返回相应文本

遍历数值列表时,先筛选满足阈值的元素,再根据结果输出列表或友好提示。推荐使用列表推导式结合条件判断,注意边界用`>=`,空列表自动为假。也可用`any()`提前终止遍历,提升效率。此法简洁,避免显式循环,特别适合阈值筛选。

Maven项目中如何强制使用本地构建的依赖版本
编程语言 · 2026-07-08

Maven项目中如何强制使用本地构建的依赖版本

多模块开发中强制使用本地依赖的正确做法是使用-SNAPSHOT版本并配合`-U`参数强制更新,或重构为多模块项目统一管理生命周期。避免使用版本范围语法或手动复制JAR,确保构建行为可靠可重复。

Go语言net.Conn并发写安全与原子性保障解析
编程语言 · 2026-07-08

Go语言net.Conn并发写安全与原子性保障解析

Go标准库中net Conn支持并发方法调用,但Write()不保证原子性。多goroutine同时写入时,系统可能拆分数据包,导致内容交错,破坏消息边界。必须使用互斥锁或bufio Writer等显式同步机制确保写操作完整性,不可依赖系统调用本身的原子性。

Python在Windows系统中获取指定卷标U盘驱动器字母的方法
编程语言 · 2026-07-08

Python在Windows系统中获取指定卷标U盘驱动器字母的方法

使用Pythonwmi库通过Win32_Volume接口查询Windows系统中卷标为“TOSHIBA”的U盘盘符。需安装wmi和pywin32,注意大小写区分及多设备过滤。仅适用于Windows。

TP6.0消息已读功能基于Redis Bitmap未读计数方案
编程语言 · 2026-07-08

TP6.0消息已读功能基于Redis Bitmap未读计数方案

TP6 0中使用Redis位图实现消息已读标记,每条消息仅占一个比特,内存效率高。需将消息ID映射为连续偏移量,通过SETBIT和GETBIT操作。需提前维护用户ID到偏移量的映射表,注意键过期与驱动类型(phpredis与predis)问题。此方法内存极省,适合海量消息场景,且需确保偏移量唯一。