Concurrent Mode Failure(并发模式失败)是CMS(Concurrent Mark Sweep)垃圾收集器特有的一种异常状态,当CMS在并发收集过程中无法正常完成回收任务时触发,可能导致系统性能急剧下降。以下是其详细解析:
1. 触发原因
CMS的核心特点是并发标记-清除,即大部分回收工作与应用线程并行执行。但在以下情况会触发Concurrent Mode Failure:
- 老年代空间耗尽:CMS在并发标记/清除阶段,应用线程仍在持续分配对象,若老年代剩余空间不足以容纳新对象,且无法等到CMS完成并发回收,JVM会紧急终止并发回收过程。
 - 元空间/永久代不足:当元空间(JDK8+)或永久代(JDK7及以前)容量不足时,即使老年代有空间,也可能触发该失败。
 - GC过程中分配大对象:若应用线程在CMS并发阶段突然分配一个大对象,而老年代剩余连续空间不足,会直接导致失败。
 
2. 后果:触发Serial Old Full GC
发生Concurrent Mode Failure后,JVM会放弃CMS的并发回收,转而启用Serial Old收集器(单线程、Stop-the-World)进行Full GC,这会带来严重影响:
- 长时间STW:Serial Old采用单线程扫描和压缩整个堆,对于大内存(如几十GB),STW时间可能达到秒级甚至分钟级,导致应用完全卡顿。
 - CPU飙升:单线程密集型的GC操作会占用大量CPU资源,同时阻塞应用线程,表现为系统CPU使用率骤升但业务处理停滞。
 - 恶性循环:若根本问题未解决(如对象分配速度超过回收速度),会频繁触发失败和Serial Old GC,形成“失败→Full GC→更慢→更易失败”的循环。
 
3. 典型日志表现
GC日志中会出现类似以下信息,明确标识Concurrent Mode Failure:
2023-10-01T12:00:00.123+0800: [GC (CMS Initial Mark) [1 CMS-initial-mark: 820000K(1024000K)] 830000K(2048000K), 0.0012345 secs] [Times: user=0.01 sys=0.00, real=0.00 secs]
2023-10-01T12:00:05.678+0800: [CMS-concurrent-mark-start]
2023-10-01T12:00:08.901+0800: [CMS-concurrent-mark: 3.222/3.222 secs] [Times: user=5.11 sys=0.23, real=3.22 secs]
2023-10-01T12:00:08.902+0800: [CMS-concurrent-preclean-start]
2023-10-01T12:00:09.103+0800: [CMS-concurrent-preclean: 0.201/0.201 secs] [Times: user=0.35 sys=0.02, real=0.20 secs]
2023-10-01T12:00:09.103+0800: [CMS-concurrent-abortable-preclean-start]
2023-10-01T12:00:15.104+0800: [CMS-concurrent-abortable-preclean: 6.001/6.001 secs] [Times: user=9.87 sys=0.56, real=6.00 secs]
2023-10-01T12:00:15.105+0800: [GC (CMS Final Remark) [YG occupancy: 100000K (1024000K)] 2023-10-01T12:00:15.105+0800: [Rescan (parallel) , 0.0123450 secs]2023-10-01T12:00:15.118+0800: [weak refs processing, 0.0001234 secs]2023-10-01T12:00:15.118+0800: [class unloading, 0.0023456 secs]2023-10-01T12:00:15.120+0800: [scrub symbol table, 0.0034567 secs]2023-10-01T12:00:15.123+0800: [scrub string table, 0.0012345 secs][1 CMS-remark: 820000K(1024000K)] 920000K(2048000K), 0.0201234 secs] [Times: user=0.08 sys=0.00, real=0.02 secs]
2023-10-01T12:00:15.125+0800: [CMS-concurrent-sweep-start]
2023-10-01T12:00:16.345+0800: [CMS-concurrent-sweep: 1.220/1.220 secs] [Times: user=1.89 sys=0.12, real=1.22 secs]
2023-10-01T12:00:17.567+0800: [GC (Allocation Failure) [ParNew: 1024000K->1024000K(1024000K), 0.0000123 secs]2023-10-01T12:00:17.567+0800: [CMS: 820000K->820000K(1024000K), 0.0000456 secs] 1844000K->1844000K(2048000K), [Metaspace: 100000K->100000K(120000K)], 0.0001234 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
2023-10-01T12:00:17.568+0800: [Full GC (Concurrent Mode Failure) [CMS: 820000K->500000K(1024000K), 5.6789012 secs] 1844000K->500000K(2048000K), [Metaspace: 100000K->99000K(120000K)], 5.6789012 secs] [Times: user=5.67 sys=0.01, real=5.68 secs]
关键特征:Full GC (Concurrent Mode Failure) 标记,且后续GC耗时极长(如示例中的5.68秒)。
4. 解决方案
(1)调整CMS触发时机
- 降低
-XX:CMSInitiatingOccupancyFraction(默认92%),如设置为70%~80%,让CMS更早开始并发回收,避免老年代空间耗尽。
(-XX:CMSInitiatingOccupancyFraction=75 -XX:+UseCMSInitiatingOccupancyOnlyUseCMSInitiatingOccupancyOnly确保严格按阈值触发,不依赖JVM自适应调整) 
(2)优化内存分配
- 避免频繁分配大对象到老年代(调整
-XX:PretenureSizeThreshold控制大对象阈值)。 - 合理设置新生代大小(
-Xmn),减少短期对象晋升到老年代的频率。 
(3)减少内存碎片
- 开启Full GC时的压缩功能:
(每次Full GC后进行内存压缩,消除碎片,但会增加STW时间)-XX:+UseCMSCompactAtFullCollection -XX:CMSFullGCsBeforeCompaction=0 
(4)扩容或更换收集器
- 若老年代确实空间不足,可适当增加堆内存(
-Xms/-Xmx)。 - 长期来看,建议替换为G1、ZGC等现代收集器,它们对并发回收和碎片处理更高效,从根本上减少此类问题。
 
总结
Concurrent Mode Failure是CMS的“致命弱点”之一,本质是并发回收速度跟不上对象分配速度。一旦发生,会触发低效的Serial Old Full GC,导致系统卡顿和CPU飙升。通过参数调优、内存优化或更换收集器,可有效规避或缓解此问题。
注意:本文归作者所有,未经作者允许,不得转载