【JVM原理详解】27-CMS收集器原理与调优
27-CMS 收集器原理与调优前面讲的收集器Serial、ParNew、Parallel Scavenge在回收老年代时都必须 STW堆越大停顿越长。对于交互式 Web 服务几百毫秒的停顿就可能导致请求超时。CMSConcurrent Mark Sweep是 HotSpot 第一款让老年代回收与用户线程并发进行的收集器把停顿从秒级降到百毫秒级曾长期是低延迟场景的首选。本篇深入剖析 CMS 的四阶段流程、三色标记算法、Concurrent Mode Failure 与内存碎片问题并给出生产级调优参数清单。CMS 的四个阶段CMS 的老年代回收分为四个阶段其中两个是并发的应用线程不停阶段1初始标记 (Initial Mark) ── STW极短 阶段2并发标记 (Concurrent Mark) ── 并发最耗时 阶段3重新标记 (Remark) ── STW较短 阶段4并发清除 (Concurrent Sweep)── 并发清理垃圾时间线应用线程: ████░░███████████████████░░██████████████████░░█████████ ↑ IM ↑ RM ↑ CS STW STW 并发 GC 线程: ──── 并发标记 ──── ──── 并发清除 ────初始标记Initial MarkSTW但耗时极短。它只标记GC Roots 能直接关联的对象即 GC Roots 的一跳邻居不遍历整个对象图。GC Roots → A → B → C → ... ↑ 初始标记只走到这一层由于范围小停顿通常几毫秒到几十毫秒。这一步依赖 ParNew 做新生代回收Minor GC来减少跨代引用扫描。并发标记Concurrent Mark并发耗时最长但不停应用。从初始标记的根开始遍历整个对象图标记所有可达对象。期间应用线程还在跑可能产生新的引用变化。这里的核心挑战是标记过程中对象引用关系在变如何保证标记正确这引出了三色标记算法。重新标记RemarkSTW暂停应用线程修正并发标记期间因引用变化导致的标记偏差。这是 CMS 中第二个 STW 点停顿通常比初始标记长但远短于并发标记。重新标记会处理并发标记期间新产生的引用——主要是通过SATBSnapshot-At-The-Beginning思路和增量更新机制确保漏标对象被补标。并发清除Concurrent Sweep并发清理未被标记的对象回收空间。这一阶段不停应用线程所以即使耗时较长也不影响延迟。缺点是清理后会产生内存碎片详见后文。三色标记算法并发标记的理论基础是三色标记Tri-color Marking把对象分为三种状态白色尚未被标记候选垃圾。灰色已被标记但其引用的对象还没全部标记待处理。黑色已被标记且其引用的对象也已全部标记存活不会被回收。初始所有对象为白色GC Roots 为灰色 过程从灰色对象出发将其引用对象标灰自身标黑 结束剩余白色对象即为垃圾[黑]A ──→ [灰]B ──→ [白]C ──→ [白]D │ └──→ [黑]E并发标记的漏标问题并发标记时应用线程可能修改引用导致两种问题问题1黑色对象指向白色对象新增引用标记前[黑]A [白]CC 即将被回收 标记后[黑]A ──→ [白]C A 新引用了 CA 已标记为黑色不会再扫描所以 C 不会被标记——但 C 实际已被引用不该回收。这就是漏标会导致存活对象被误回收是致命错误。问题2灰色对象断开到白色对象的引用标记前[灰]B ──→ [白]C C 等待 B 扫描 标记后[灰]B ──✗ B 断开了对 C 的引用但 C 被其他黑对象引用如果 B 是唯一会扫描到 C 的灰色对象断开后 C 永远不会被标灰——同样漏标。CMS 的解决方案增量更新CMS 用增量更新Incremental Update解决问题1当黑色对象新指向白色对象时记录这次写操作。重新标记阶段把这些黑色→白色的引用重新扫描一遍补标为灰色。// 伪代码CMS 的写屏障voidfieldWrite(ObjectblackObj,Fieldf,ObjectwhiteObj){if(isBlack(blackObj)isWhite(whiteObj)){cardTable.mark(blackObj);// 记录到 Card Table}// 实际写入blackObj.fwhiteObj;}重新标记时遍历 Card Table重新扫描这些黑色对象。这就是重新标记存在的根本原因——它要补救并发期间的漏标。注意G1 用的是SATB在并发开始时拍快照思路不同但目标一致下一篇会详述。Concurrent Mode FailureCMS 并发回收的代价是回收速度跟不上分配速度时老年代空间不够用。这时触发Concurrent Mode Failure。触发条件CMS 在并发阶段标记或清除期间应用线程还在分配对象进入老年代。如果老年代空间耗尽而 CMS 还没回收完就会触发 Full GC退化为 Serial Old单线程、STW、Mark-Compact。整个堆停顿可能几秒到十几秒。时间线 应用分配: ──→ 老年代快满 ──→ 继续分配 ──→ 老年代耗尽 ──→ Concurrent Mode Failure CMS 回收: 并发标记中 ──────────────→ 还没回收完 ──→ 降级 Serial Old为什么降级为 Serial Old因为此时老年代空间已耗尽无法继续并发回收并发回收需要额外空间做标记。唯一能做的就是 STW、全堆整理——而 CMS 自身没有 STW Full GC 实现只能借用 Serial Old。这是 CMS 最大的痛点一次 Concurrent Mode Failure 可能让停顿从 50ms 飙到 5 秒对延迟敏感的系统是灾难。预防策略调低触发阈值让 CMS 提早开始回收见CMSInitiatingOccupancyFraction。扩大老年代给回收留出更多空间余量。降低分配速率优化业务代码减少大对象分配。内存碎片问题CMS 用标记-清除Mark-Sweep算法不整理内存。长期运行后老年代会出现大量碎片[占用][空][占用][空空][占用][空][占用][空空空] ↑ 碎片总和够但不连续当需要分配一个 5MB 大对象碎片总和有 10MB 但最大连续块只有 2MB 时分配失败——触发 Full GC 整理碎片。Full GC with Compact碎片严重时CMS 会触发一次Full GC CompactSerial Old 单线程整理STW。整理后碎片消失但停顿很长。[占用][空][占用][空空][占用] → [占用占用占用][空空空空空空] 整理前碎片 整理后连续这就是 CMS 虽然标榜低延迟但偶尔的长停顿常被诟病的原因日常 GC 很快但碎片触发 Full GC 时可能数秒。关键调优参数-XX:CMSInitiatingOccupancyFraction设置老年代占用率阈值达到后触发 CMS 回收-XX:CMSInitiatingOccupancyFraction70默认值是92%JDK 8太高了——意味着老年代用到 92% 才开始回收留给并发回收的空间很紧容易 Concurrent Mode Failure。生产建议设70-80给并发回收留足余量。配合-XX:UseCMSInitiatingOccupancyFraction使用JDK 8 需显式开启手动模式-XX:UseConcMarkSweepGC\-XX:UseCMSInitiatingOccupancyFraction\-XX:CMSInitiatingOccupancyFraction75-XX:UseCMSCompactAtFullCollection开启后每次 Full GC 后做内存整理默认开启。关闭则只清除不整理停顿短但碎片累积。-XX:UseCMSCompactAtFullCollection# 开启整理默认-XX:CMSFullGCsBeforeCompaction0# 多少次 Full GC 后整理0每次都整理由于 CMS Full GC 已经是 STW整理多花的几十毫秒通常可接受。一般保持默认。-XX:CMSScavengeBeforeRemark重新标记前先做一次 Minor GC。好处新生代里的垃圾先清掉减少重新标记要扫描的跨代引用缩短重新标记停顿。-XX:CMSScavengeBeforeRemark强烈建议开启尤其当新生代较大时。代价是多了次 Minor GC但通常物有所值。-XX:ParallelCMSThreadsCMS 并发线程数默认(ParallelGCThreads 3) / 4。太多会挤占应用 CPU太少回收跟不上。一般保持默认CPU 紧张时可下调。调优参数清单下面是一份生产级 CMS 参数模板JDK 8按需调整java-Xms4g-Xmx4g-Xmn1g\-XX:UseConcMarkSweepGC-XX:UseParNewGC\-XX:CMSInitiatingOccupancyFraction70\-XX:UseCMSInitiatingOccupancyFraction\-XX:CMSScavengeBeforeRemark\-XX:UseCMSCompactAtFullCollection\-XX:CMSFullGCsBeforeCompaction0\-XX:ParallelGCThreads8\-XX:ConcGCThreads2\-XX:PrintGCDetails-XX:PrintGCDateStamps\-Xloggc:/var/log/gc.log\-cpMyApp com.example.Main要点堆固定-Xms -Xmx避免堆扩展触发额外 GC。新生代 1GB约占堆 25%给老年代留足空间。阈值 70%老年代到 70% 就回收余量充足。重新标记前 Minor GC减少重新标记停顿。GC 日志必开用于事后分析。代码示例制造 CMS Full GC/** * 演示 CMS 行为与 Concurrent Mode Failure * 适用 JDK 8 * * 运行 * java -Xms1g -Xmx1g -Xmn256m * -XX:UseConcMarkSweepGC -XX:UseParNewGC * -XX:CMSInitiatingOccupancyFraction70 * -XX:UseCMSInitiatingOccupancyFraction * -XX:PrintGCDetails -XX:PrintGCDateStamps * -Xloggc:gc.log -cp MyApp CmsGcDemo */publicclassCmsGcDemo{staticfinalint_1MB1024*1024;staticfinaljava.util.Listbyte[]CACHEnewjava.util.ArrayList();publicstaticvoidmain(String[]args)throwsException{// 持续往老年代填充制造压力for(inti0;i1000;i){CACHE.add(newbyte[2*_1MB]);// 大对象直接进老年代if(i%50)CACHE.subList(0,CACHE.size()/2).clear();// 偶尔清理制造碎片Thread.sleep(10);}}}观察日志中的关键字段# 并发标记开始 [2026-07-17T10:00:01.234] [GC [CMS-concurrent-mark-start] # 并发标记结束 [2026-07-17T10:00:02.567] [CMS-concurrent-mark: 1.333/1.333 secs] # 初始标记STW [2026-07-17T10:00:01.000] [GC (CMS Initial Mark) [1 CMS-initial-mark: 600M(768M)] 800M(1024M), 0.012 secs] # 重新标记STW [2026-07-17T10:00:02.400] [GC (CMS Final Remark) [1 CMS-remark: 650M(768M)] 850M(1024M), 0.045 secs] # Concurrent Mode Failure灾难 [2026-07-17T10:00:03.000] [GC (CMS Mode failure): 768M(768M) 1024M(1024M) 5.678 secs]看到CMS Mode failure就说明 CMS 没顶住触发了 Serial Old Full GC——这时就该调阈值或扩老年代了。CMS 的衰落CMS 在 JDK 9 被标记deprecatedJDK 14 被彻底移除。原因内存碎片Mark-Sweep 固有问题Full GC 整理停顿不可控。Concurrent Mode Failure高分配速率下不可预测的降级。浮动垃圾并发期间产生的垃圾本轮回收不掉。代码维护负担CMS 实现复杂G1 已经能更好满足低延迟需求。新项目不应再用 CMS。JDK 11 直接用 G1JDK 15 考虑 ZGC/Shenandoah。但理解 CMS 对学习 G1、ZGC 的并发回收思路至关重要——它们都站在 CMS 的肩膀上。实践要点1. 阈值宁低勿高默认 92% 太激进。生产环境设 70-80宁可多回收几次也别等耗尽。2. 监控 Concurrent Mode FailureCMS 日志里出现concurrent mode failure就是红线报警。即使一周一次也要追查原因——通常是分配速率突增或老年代太小。3. 大对象是 CMS 杀手大对象如大数组、大字符串直接进老年代快速消耗空间。如果业务有大量大对象分配考虑限制单次分配大小。复用缓冲区避免频繁创建。4. 浮动垃圾不可避免并发标记期间产生的垃圾本轮回收不掉只能等下次。这是 CMS 并发设计的固有代价无法消除只能靠提高回收频率缓解。5. 迁移到 G1 的时机JDK 升级到 11直接切 G1。堆超过 4GBG1 分区回收比 CMS 更可控。Concurrent Mode Failure 频发G1 的 Mixed GC 能更好处理碎片。小结CMS是第一款让老年代回收与用户线程并发的收集器四个阶段中初始标记和重新标记STW并发标记和并发清除与应用并发。三色标记黑灰白是并发标记的理论基础CMS 用增量更新解决黑色对象新引用白色对象的漏标问题。Concurrent Mode Failure是 CMS 最大的痛点老年代耗尽时降级为 Serial Old停顿可能数秒靠调低触发阈值预防。内存碎片是 Mark-Sweep 的固有缺陷靠UseCMSCompactAtFullCollection在 Full GC 后整理缓解。关键调优参数CMSInitiatingOccupancyFraction70、CMSScavengeBeforeRemark、固定堆大小JDK 14 后 CMS 已移除新项目应迁移到 G1 或 ZGC。下一篇我们进入 G1——它用分区化设计解决了 CMS 的碎片和 Full GC 不可控问题是 JDK 9 的默认收集器也是现代 JVM 调优的核心。更多内容JVM调优实战

相关新闻

计算机毕业设计之基于springboot+vue的电影院购票管理系统

计算机毕业设计之基于springboot+vue的电影院购票管理系统

信息技术是当今社会发展的重要方向之一,它已经深入到各个行业中。随着计算机技术的发展,信息技术已经从传统的数据处理转变为网络信息的处理和交互。在管理方面,通过信息管理技术,系统可以快速的处理大量的数据,并且能…

2026/7/31 23:58:09阅读更多 →
微服务系统分析与设计

微服务系统分析与设计

微服务系统测试微服务架构的采用使得软件开发和交付过程更加敏捷,但也带来了新的挑战。其中之一就 是如何有效地测试微服务系统。微服务系统的分布式特性和服务之间的通信使得传统的测试方 法和工具无法直接应用。因此,有必要深入研究微服务系统测试的特…

2026/7/31 23:56:09阅读更多 →
C++智能指针:std::make_shared的原理、优势与使用场景详解

C++智能指针:std::make_shared的原理、优势与使用场景详解

1. 项目概述:为什么我们需要std::make_shared在C的日常开发中,尤其是涉及到资源管理和对象生命周期时,智能指针是我们绕不开的话题。从C11开始,std::shared_ptr成为了管理动态分配对象、实现共享所有权的标准工具。然而&#xff0…

2026/7/31 23:56:09阅读更多 →
Grok 4.5两周主力实测:代码、检索、推理与Agent场景能否替代GPT-5.6

Grok 4.5两周主力实测:代码、检索、推理与Agent场景能否替代GPT-5.6

GPT-5.6好用但贵,Grok 4.5免费但质量差一些——这是大部分人的印象。但到底差多少?哪些场景能替代、哪些不能?我把Grok 4.5当主力用了两周,从代码辅助到知识检索到逻辑推理到Agent,逐个场景跟GPT-5.6做了对比。结论是&…

2026/8/1 1:00:34阅读更多 →
LoadBalancer负载均衡:集群高可用调用优化

LoadBalancer负载均衡:集群高可用调用优化

LoadBalancer负载均衡:集群高可用调用优化一个服务三个节点,请求来了该打给谁?你总不能闭着眼睛随机点一个吧——那叫"非洲大草原式负载均衡"。今天聊聊 SpringCloud 官方的 LoadBalancer,让你的请求分配得明明白白。一…

2026/8/1 1:00:34阅读更多 →
无人机编队控制:自适应滑模与神经网络容错技术

无人机编队控制:自适应滑模与神经网络容错技术

1. 项目背景与核心挑战主从式无人机编队控制在军事侦察、农业植保、灾害救援等领域具有广泛应用前景。这种控制模式通常由一架领航无人机(主节点)和多架跟随无人机(从节点)组成,通过无线通信实现协同飞行。在实际应用中…

2026/8/1 1:00:34阅读更多 →
2026年制造业短视频运营公司深度评测:工厂短视频获客选型参考

2026年制造业短视频运营公司深度评测:工厂短视频获客选型参考

数字营销新浪潮:短视频AI搜索重构制造企业获客路径时代背景与行业数据2026年,数字营销正式进入短视频与AI搜索深度融合的新阶段。抖音、视频号、小红书等平台凭借精准的算法推荐与搜索能力,成为工业品、制造业、工程建设等ToB高客单行业品牌曝…

2026/8/1 0:58:32阅读更多 →
UiPath Community Register

UiPath Community Register

https://cloud.uipath.com/portal_/register打开链接 → 注册账号(QQ/163 等个人邮箱均可,无需企业邮箱) 注册类型选择 Community(社区版免费方案) 邮箱验证完成,进入云端控制台 左侧菜单【资源中心 Resour…

2026/8/1 0:58:29阅读更多 →
PUTTY.EXE  PSCP.EXE

PUTTY.EXE PSCP.EXE

Microsoft Windows [版本 6.1.7601] 版权所有 (c) 2009 Microsoft Corporation。保留所有权利。C:\Users\Administrator>d:D:\> D:\> D:\>cd D:\puttyD:\putty> D:\putty>Linux → WindowsD:\putty>pscp admin192.168.1.110:/home/oceanbase-4.3.5.5-1050…

2026/8/1 0:58:28阅读更多 →
覆盖国产 + 海外 + 开源模型,OpenClaw 2.7.9 Windows/Mac 双端部署详解

覆盖国产 + 海外 + 开源模型,OpenClaw 2.7.9 Windows/Mac 双端部署详解

🔹 工具基础介绍 OpenClaw 是开源生态中一款实用性较强的本地智能工具,凭借本地离线运行、可视化图形操作和任务自动化三大核心特性,赢得了众多用户的青睐。与普通在线对话AI工具不同,它属于能够直接操控本机软硬件的智能数字员工…

2026/7/31 20:44:05阅读更多 →
伺服阀焊完微漏毁整机?精密激光焊接三关锁住高压

伺服阀焊完微漏毁整机?精密激光焊接三关锁住高压

所谓液压伺服阀体的精密激光焊接,是用激光束对阀座壳体(通常为不锈钢或铝合金)进行密封焊接,使阀体在21-35MPa的高压液压油或压缩气体中长期运行而不发生介质泄漏。液压伺服阀是高端液压系统的"大脑"。从航空航天飞行控…

2026/7/31 17:41:43阅读更多 →
D2DX:三步实现《暗黑破坏神2》高清宽屏体验的终极指南

D2DX:三步实现《暗黑破坏神2》高清宽屏体验的终极指南

D2DX:三步实现《暗黑破坏神2》高清宽屏体验的终极指南 【免费下载链接】d2dx D2DX is a complete solution to make Diablo II run well on modern PCs, with high fps and better resolutions. 项目地址: https://gitcode.com/gh_mirrors/d2/d2dx 你是否还在…

2026/7/31 20:44:05阅读更多 →
无损视频剪辑终极指南:如何实现快速高效的多媒体处理

无损视频剪辑终极指南:如何实现快速高效的多媒体处理

无损视频剪辑终极指南:如何实现快速高效的多媒体处理 【免费下载链接】lossless-cut The swiss army knife of lossless video/audio editing 项目地址: https://gitcode.com/gh_mirrors/lo/lossless-cut 在数字媒体创作领域,视频编辑处理的质量损…

2026/8/1 0:00:10阅读更多 →
AI辅助本科论文写作:8大工具评测与高效使用指南

AI辅助本科论文写作:8大工具评测与高效使用指南

1. 本科生论文写作的AI辅助现状本科毕业论文是每个大学生必须跨越的一道坎。记得我当年写论文时,光是文献检索就花了整整两周时间,打印的参考文献堆满了半个书桌。如今AI技术的发展为学术写作带来了革命性变化,合理使用这些工具可以节省80%以…

2026/8/1 0:00:10阅读更多 →
如何快速配置大麦自动抢票系统:从零开始搭建Python抢票助手

如何快速配置大麦自动抢票系统:从零开始搭建Python抢票助手

如何快速配置大麦自动抢票系统:从零开始搭建Python抢票助手 【免费下载链接】ticket-purchase 大麦自动抢票,支持人员、城市、日期场次、价格选择 项目地址: https://gitcode.com/GitHub_Trending/ti/ticket-purchase 还在为抢不到热门演唱会门票…

2026/8/1 0:00:10阅读更多 →
无损视频剪辑终极指南:如何实现快速高效的多媒体处理

无损视频剪辑终极指南:如何实现快速高效的多媒体处理

无损视频剪辑终极指南:如何实现快速高效的多媒体处理 【免费下载链接】lossless-cut The swiss army knife of lossless video/audio editing 项目地址: https://gitcode.com/gh_mirrors/lo/lossless-cut 在数字媒体创作领域,视频编辑处理的质量损…

2026/8/1 0:00:10阅读更多 →
AI辅助本科论文写作:8大工具评测与高效使用指南

AI辅助本科论文写作:8大工具评测与高效使用指南

1. 本科生论文写作的AI辅助现状本科毕业论文是每个大学生必须跨越的一道坎。记得我当年写论文时,光是文献检索就花了整整两周时间,打印的参考文献堆满了半个书桌。如今AI技术的发展为学术写作带来了革命性变化,合理使用这些工具可以节省80%以…

2026/8/1 0:00:10阅读更多 →
如何快速配置大麦自动抢票系统:从零开始搭建Python抢票助手

如何快速配置大麦自动抢票系统:从零开始搭建Python抢票助手

如何快速配置大麦自动抢票系统:从零开始搭建Python抢票助手 【免费下载链接】ticket-purchase 大麦自动抢票,支持人员、城市、日期场次、价格选择 项目地址: https://gitcode.com/GitHub_Trending/ti/ticket-purchase 还在为抢不到热门演唱会门票…

2026/8/1 0:00:10阅读更多 →