为什么 Java 中 CMS 垃圾收集器在发生 Concurrent Mode Failure 时的 Full GC 是单线程的?

在 CMS(Concurrent Mark-Sweep)垃圾收集器中,当发生 Concurrent Mode Failure 时,JVM 会执行一次 Full GC。与并发多线程的垃圾回收相比,这种 Full GC 是单线程的,导致暂停时间显著增加。

以下是具体原因及原理分析:


1. CMS 的设计目标

CMS 的核心目标是 低停顿,通过并发执行标记和清除阶段,与应用线程同时运行,最大限度地减少垃圾回收引起的停顿。然而,CMS 的标记-清除算法本质上 不进行内存压缩,因此在某些情况下(如内存碎片严重或空间不足),CMS 无法完成任务,从而触发 Concurrent Mode Failure


2. Full GC 的触发原因

当 CMS 失败时,老年代空间不足,无法存放新分配或晋升的对象,这时 JVM 只能退而求其次,执行一次 Full GC 来回收整个堆空间。这种 Full GC 的特点是:

  • 暂停所有应用线程(Stop-The-World)。
  • 使用单线程执行标记、清理和内存整理操作。

3. 为什么 Full GC 是单线程的?

CMS 的 Full GC 是基于 Serial Old GC 的单线程实现,其设计原因如下:

原因 1:CMS 的备用策略

CMS 是为低延迟场景设计的,但它的设计并不适合 Full GC。当 CMS 失败时,JVM 转而调用传统的 Serial Old GC 作为备用策略。Serial Old GC 是单线程的,因此 CMS 的 Full GC 也只能是单线程。

原因 2:内存压缩需求

CMS 本身不支持 内存压缩(Compact),而 Full GC 在清理垃圾的同时,还需要对内存进行压缩以消除碎片化问题。这种压缩操作涉及对象移动和引用更新,较为复杂,单线程执行可以避免多线程同步带来的额外开销。

原因 3:历史兼容性

早期的 JVM 中,Serial Old GC 是默认的老年代垃圾回收器。当 CMS 失败时,JVM 选择直接使用现有的 Serial Old GC 实现 Full GC,而没有针对多线程优化。

原因 4:代码复杂性与性能权衡

在设计 CMS 时,Full GC 被视为一种 非常规操作,只在少数情况下触发。因此,JVM 没有对 CMS 的 Full GC 实现多线程优化,因为这会显著增加代码复杂性,而收益有限。


4. Full GC 的影响

Full GC 是单线程的,因此其执行时间较长,会显著增加应用的停顿时间。这对于低延迟应用是不利的。以下是其典型影响:

  • 应用暂停时间从毫秒级增加到秒级。
  • 高并发环境下会导致性能抖动。

5. 如何避免 Full GC?

为避免 Concurrent Mode Failure 和 Full GC 的发生,可以采取以下措施:

  1. 调整 CMS 启动阈值

    • 使用 -XX:CMSInitiatingOccupancyFraction=<N> 提前启动 CMS 回收,避免内存空间被耗尽。
  2. 增加老年代大小

    • 调整 -Xmx-XX:NewRatio,为老年代分配更多内存空间。
  3. 优化对象分配和晋升

    • 减少长生命周期对象直接分配到老年代,优化代码逻辑,降低新生代到老年代的晋升压力。
  4. 启用内存压缩

    • 使用 -XX:+UseCMSCompactAtFullCollection 启用内存压缩,减少碎片化问题。
  5. 使用其他垃圾回收器

    • 如果应用无法接受 CMS 的 Full GC 停顿时间,可以尝试使用 G1 GC 或其他现代垃圾回收器(如 ZGC、Shenandoah),这些回收器更适合低延迟场景。

6. 总结

CMS 在设计上并不擅长处理 Full GC,发生 Full GC 时转而调用单线程的 Serial Old GC。其原因主要在于历史兼容性、内存压缩需求,以及复杂性与收益的权衡。

核心要点:

  1. CMS 的 Full GC 是单线程的,因为它依赖 Serial Old GC 的实现。
  2. Full GC 主要用于清理碎片化内存,同时进行压缩。
  3. 为避免 Full GC,需要合理配置 CMS 参数,优化对象分配策略,或使用其他现代垃圾回收器。

合理的配置和调优可以大幅减少 Concurrent Mode Failure 的风险,降低 Full GC 对应用性能的影响。

为什么 Java 中 CMS 垃圾收集器在发生 Concurrent Mode Failure 时的 Full GC 是单线程的?的更多相关文章

  1. 《深入理解Java虚拟机》垃圾收集器

    说起垃圾收集(Garbage Collection,GC),大部分人都把这项技术当做Java语言的伴生产物.事实上,GC的历史远比Java久远,1960年诞生于MIT的Lisp是第一门真正使用内存动态 ...

  2. 想买保时捷的运维李先生学Java性能之 垃圾收集器

    前言 垃圾收集算法是内存回收的方法论:垃圾收集器是内存回收的具体实现.Java虚拟机规范中对垃圾收集器应该如何实现并没有任何规定,因此不同的厂商.不同版本的虚拟机所提供的垃圾收集器都有很大的差别,并且 ...

  3. 【JVM】JVM中的垃圾收集器

    垃圾收集器组合 Serial+Serial Old Serial+CMS ParNew+CMS ParNew+Serial Old Paralle Scavenge + Serial Old Para ...

  4. G1垃圾收集器和CMS垃圾收集器 (http://mm.fancymore.com/reading/G1-CMS%E5%9E%83%E5%9C%BE%E7%AE%97%E6%B3%95.html#toc_8)

    参考来源 JVM 体系架构 堆/栈的内存分配 静态和非静态方法的内存分配 CMS 回收算法 应用场景 CMS 垃圾收集阶段划分(Collection Phases) CMS什么时候启动 CMS缺点 G ...

  5. CMS垃圾收集器

    介绍 CMS垃圾回收器的全称是Concurrent Mark-Sweep Collector,从名字上可以看出两点,一个是使用的是并发收集,第二个是使用的收集算法是Mark-Sweep.从而也可以推测 ...

  6. 2. Java中的垃圾收集 - GC参考手册

    标记-清除(Mark and Sweep)是最经典的垃圾收集算法.将理论用于生产实践时, 会有很多需要优化调整的地点, 以适应具体环境.下面通过一个简单的例子, 让我们一步步记录下来, 看看如何才能保 ...

  7. 深入理解Java虚拟机笔记——垃圾收集器与内存分配策略

    目录 判断对象是否死亡 引用计数器算法 可达性分析算法 各种引用 回收方法区 垃圾收集算法 标记-清除算法 复制算法 标记-整理算法 分代收集算法 HotSpot算法实现 枚举根节点 GC停顿(Sto ...

  8. 实例透彻分析CMS垃圾收集器执行过程

    CMS收集器收集步骤: 在上一次[https://www.cnblogs.com/webor2006/p/11055468.html]中已经对CMS的垃圾收集器有了一定的理论上的了解,其中提到了CMS ...

  9. 稳了!我准备了1个晚上的CMS垃圾收集器

    面试官:今天还是来聊聊CMS垃圾收集器呗? 候选者:嗯啊... 候选者:如果用Seria和Parallel系列的垃圾收集器:在垃圾回收的时,用户线程都会完全停止,直至垃圾回收结束! 候选者:CMS的全 ...

  10. Java虚拟机学习 - 垃圾收集器

    HotSpot JVM收集器 上面有7中收集器,分为两块,上面为新生代收集器,下面是老年代收集器.如果两个收集器之间存在连线,就说明它们可以搭配使用. Serial(串行GC)收集器 Serial收集 ...

随机推荐

  1. 变量-python

    变量-python 1. 变量的定义 变量是存储数据的地方,在程序运行时,变量的值可以改变.变量的定义格式如下: 变量名 = 数据 例如: a = 10 b = "hello" c ...

  2. flutter中 ListView的使用

    1.ListView的简单介绍 ListView是最常用的可以滚动组件之一, 它可以沿一个方向进行线性排列所有的子组件. 下面是ListView的属性值介绍: scrollDirection:列表的滚 ...

  3. ceph数据重构原理

    本文分享自天翼云开发者社区<ceph数据重构原理>,作者:x****n 在分布式存储系统Ceph中,硬盘故障是一种常见问题.为了保证数据安全,当发生硬盘故障后,分布式存储系统会依据算法对故 ...

  4. 『Python底层原理』--Python整数为什么可以无限大

    整数类型是编程中最常见的数据类型之一,但它的实现细节却鲜为人知. 与其他语言不同,Python 的整数是任意精度的,这意味着它们可以无限大,仅受限于内存. 这种特性使得 Python 在处理大整数时非 ...

  5. FishSpeech应用篇——专属朗读人

    背景 FishSpeech部署教程参见:使用FishSpeech进行语音合成推理 - 天命小猪 - 博客园 部署好之后,就能够基于推理来定制自己专属朗读人.编程能力强的小伙伴可以结合AI定制一个自己的 ...

  6. 大量小文件不适合存储于HDFS的原因

    1.小文件过多,会过多占用namenode的内存,并浪费block. - 文件的元数据(包括文件被分成了哪些blocks,每个block存储在哪些服务器的哪个block块上),都是存储在namenod ...

  7. C#(面向对象的托管语言)类库(区别于应用程序)的异常处理思路

    1.不要做出任何应用程序才需要考虑抉择策略,不能想当然的决定一些错误情形.具体的一个体现形式是什么异常都捕获.这不是类库的职责,因为无法掌握所有的调用者的使用情形,这些不确定性是委托.虚方法.接口等特 ...

  8. 洛谷P4390 [BalkanOI2007] Mokia 摩基亚 题解

    题目传送门. 想必 我的另外一篇题解 已经把这道题的思路说的很清楚了,但是那道题是把所有的修改全部告诉你,然后再一个一个问你矩阵和,但是这道题他是修改中夹着询问,但是没有关系,我们照样可做. 考虑将所 ...

  9. 「四」vim执行外部命令、文件另存为、文件提取合并、打开类命令、光标后插入内容、替換、复制粘贴、查找设置

    vim执行外部命令 查看当前目录文件::! command 另存为 完整内容: :w filename 选择性内容: v:选择内容. :w filename 文件提取合并 向当前文件插入文件内容: : ...

  10. 咨询公司:趁着AI人工智能的浪潮还能持续,好好享受吧……

    在人工生成式智能热潮的喧嚣与狂热之中,咨询行业正经历一场基本未被察觉却极具变革性的革命,这场变革将塑造它的未来. 传统咨询依赖于由高素质专业人士组成的团队,他们专注于研究.数据分析,并提供定制化建议. ...