为什么 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. 浅谈云主机在VPC中进行迁移的使用场景和操作方法

    本文分享自天翼云开发者社区<浅谈云主机在VPC中进行迁移的使用场景和操作方法>,作者:刘****雪 一.客户经常遇到的网络迁移问题 客户在天翼云购买一台云主机并且部署完成想要的应用后,发现 ...

  2. 欧拉积分(Genshin)

    \(\Gamma\) 函数 引入.定义 在计算组合数式子的时候,我们时常会看到这样的式子: \[\frac{(-2n)!((-n/2)!)^2}{((-n)!)^3} \] 然而,我们不知道什么是负数 ...

  3. Clickhouse常见异常

    一.异常 1)DB::Exception: Nested type Array(String) cannot be inside Nullable type (version 20.4.6.53 (o ...

  4. 最新demo版|如何0-1开发支付宝小程序之如何调试小程序(二)

    上一篇跟大家详细的讲了下开发支付宝小程序前所需要做准备事项,安装了支付宝小程序的开发工具.那么今天就来详细聊一下在小程序开发工具中,我们需要如何调试小程序. 支付宝小程序的调试分为三种,分别是「模拟器 ...

  5. 泰山派(Ubuntu 20.0)更换软件源

    泰山派更换软件源 1.编辑apt软件包源获取文件 vim /etc/apt/sources.list 2.更换为下面的源 deb http://mirrors.ustc.edu.cn/ubuntu-p ...

  6. MySQL - [09] 正则表达式

    转载:https://mp.weixin.qq.com/s/7RavuYGs9SthX2pxGJppqw select * from t1 where name rlike '^[a-zA-Z]+$' ...

  7. Halcon学习教程(二) 测量量测相关(点到线距离,线到线距离,轮廓线距离,一维测量,圆形测量,矩形测量等)

    原文作者:aircraft 原文地址:https://www.cnblogs.com/DOMLX/p/18740576 本篇讲一些测量用到的算子和实例,想了解更多就得去看看halcon实例里一维测量里 ...

  8. deepseek-llamafactory模型微调并转为gguf

    模型微调测试 基础设施配置 使用云计算平台 使用vscode进行配置 打开系统盘文件夹 llamafactory基础配置 git clone --depth 1 https://github.com/ ...

  9. rust学习笔记(3)

    变量 变量默认是不可变的 不能使用没有初始化的变量 作用域 变量离开作用域之后会直接释放, 无法再次使用; 在内部代码块中定义的变量会导致外部的变量被遮蔽 类型转换 部分类型可以隐式转换, 部分类型需 ...

  10. linux生成ssh密钥

    前言 我们一般使用 PuTTY 等 SSH 客户端来远程管理 Linux 服务器.但是,一般的密码方式登录,容易有密码被暴力破解的问题.所以,一般我们会将 SSH 的端口设置为默认的 22 以外的端口 ...