深入浅出JVM(十七)之并发垃圾收集器CMS

简介: 深入浅出JVM(十七)之并发垃圾收集器CMS

上篇文章介绍用户线程与GC线程并发执行时可能产生的问题以及使用三色标记法演示原始快照和增量更新两种解决方案

这篇文章将主要介绍并发垃圾收集器中的CMS,其中CMS使用增量更新来解决对象消失问题,如果不了解增量更新的同学可以查看上篇文章深入浅出JVM(十六)之三色标记法与并发可达性分析

前言

前文描述过,当GC时需要枚举的GC根节点需要极短的停顿(STW)

而在遍历GC引用链时,如果用户线程是停顿的,那么不会改变引用,GC线程遍历标识即可

但随着堆内存中对象的增多,引用链会越来越长,如果持续让用户线程停顿,在某些需要低延迟的场景是不理想的

因此希望能在这个环节让用户线程和GC线程能够并发执行,并发执行就会存在改变对象引用,可能导致对象消失问题,其中可以使用增量更新和原始快照的方式解决,而CMS使用的就是增量更新

Concurrent Mark Sweep

CMS全称Concurrent Mark Sweep 并发标记清除收集器

CMS是老年代收集器,采用标记-清除算法,年轻代常用ParNew收集器,以最短停顿时间(低延迟)为目标的收集器

CMS并没有使用标记-整理算法,因为标记、清理阶段是和用户线程并发执行的,如果使用标记-整理算法可能会导致移动引用的位置导致出错

执行步骤

  1. 初始标记: 标记GC Roots直接关联的对象(STW时间极短)
  2. 并发标记: 从GC Roots直接关联对象开始遍历整个引用链的过程(耗时长,不需要停顿用户线程,用户线程与GC线程并发执行)
  3. 重新标记: 使用增量更新避免对象消失问题,修正并发标记期间改动的对象(需要STW,耗时比步骤1长,比步骤2短)
  4. 并发清除: 清理标记阶段判断已死亡的对象、重置状态等(该阶段也是并发执行)

执行图

image.png

参数设置

  • -XX:UseConcMarkSweepGC
  • 老年代使用CMS垃圾收集器,新生代使用ParNew收集器
  • -XX:CMSInitiatingOccupancyFraction
  • 设置老年代使用多少空间时开始垃圾回收
  • 如果设置的太高,不够内存分配,不能满足并发执行,就会冻结用户线程启动Serial Old收集器,停顿时间就会变长
  • 如果内存增长缓慢可以设置高一些,如果内存增长很快就要设置低一些 默认92%
  • -XX:+UseCMSCompactAtFullCollection
  • 指定在FULL GC后是否对内存进行压缩整理
  • 开启后,通过-XX:CMSFullGCsBeforeCompaction设置执行多少次FULL GC后进行内存压缩整理
  • -XX:ParallelCMSThreads
  • 设置GC线程数量

特点

优点:

  1. 停顿时间短
    只在初始标记,重新标记时STW
  2. 并发执行
    时间长的并发标记和并发清理与用户线程,加快响应速度,提升用户体验

缺点:

  1. 吞吐量降低
    在处理器核数少时,GC线程与用户线程并发执行(使用i-CMS解决:减少GC线程独占时间,垃圾回收时间变长,对用户线程执行影响变小)
  2. 无法处理浮动垃圾
    增量更新通过记录新增引用来避免对象消失问题,可能出现浮动垃圾(不能在这一次的GC中被回收,只能下一次GC时被回收)
    CMS不能等老年代满了再垃圾回收,因为与用户线程并发执行,所以需要留一部分内存
  3. 内存碎片多
    多次垃圾回收后进行一次标记-整理算法,采用替补方案Serial Old

总结

本文根据并发垃圾收集器CMS深入浅出的解析CMS执行流程、优缺点以及配置参数等

CMS是一款主打低延迟、使用标记-清除算法的老年代并发垃圾收集器,年轻代常使用ParNew

CMS在初始标记时进行STW,接下来遍历引用链时与用户线程并发执行,然后让用户线程短暂STW使用增量更新进行重新标记,最后在并发进行清理、重置等工作

CMS的特点是在遍历引用链、清理时并发执行,能够使用户线程的停顿时间变短;但是带来吞吐量的降低,并且增量更新会导致浮动垃圾的出现,由于老年代使用标记-清除算法,不整理内存将会导致大对象无法存储,替补方案是使用Serial Old单线程标记-整理

如果老年代内存不足或需要整理内存时,会使用Serial Old 单线程处理,这可能导致延迟更高,在高版本中已经有G1等其他垃圾收集器代替CMS,CMS在JDK14时被移除

最后(一键三连求求拉~)

本篇文章将被收入JVM专栏,觉得不错感兴趣的同学可以收藏专栏哟~

本篇文章笔记以及案例被收入 gitee-StudyJavagithub-StudyJava 感兴趣的同学可以stat下持续关注喔~

有什么问题可以在评论区交流,如果觉得菜菜写的不错,可以点赞、关注、收藏支持一下~

关注菜菜,分享更多干货,公众号:菜菜的后端私房菜

相关文章
|
2月前
|
缓存 算法 Java
JVM知识体系学习六:JVM垃圾是什么、GC常用垃圾清除算法、堆内存逻辑分区、栈上分配、对象何时进入老年代、有关老年代新生代的两个问题、常见的垃圾回收器、CMS
这篇文章详细介绍了Java虚拟机(JVM)中的垃圾回收机制,包括垃圾的定义、垃圾回收算法、堆内存的逻辑分区、对象的内存分配和回收过程,以及不同垃圾回收器的工作原理和参数设置。
89 4
JVM知识体系学习六:JVM垃圾是什么、GC常用垃圾清除算法、堆内存逻辑分区、栈上分配、对象何时进入老年代、有关老年代新生代的两个问题、常见的垃圾回收器、CMS
|
2月前
|
存储 监控 算法
JVM调优深度剖析:内存模型、垃圾收集、工具与实战
【10月更文挑战第9天】在Java开发领域,Java虚拟机(JVM)的性能调优是构建高性能、高并发系统不可或缺的一部分。作为一名资深架构师,深入理解JVM的内存模型、垃圾收集机制、调优工具及其实现原理,对于提升系统的整体性能和稳定性至关重要。本文将深入探讨这些内容,并提供针对单机几十万并发系统的JVM调优策略和Java代码示例。
63 2
|
2月前
|
Java
JVM进阶调优系列(5)CMS回收器通俗演义一文讲透FullGC
本文介绍了JVM中CMS垃圾回收器对Full GC的优化,包括Stop the world的影响、Full GC触发条件、GC过程的四个阶段(初始标记、并发标记、重新标记、并发清理)及并发清理期间的Concurrent mode failure处理,并简述了GC roots的概念及其在GC中的作用。
|
4月前
|
存储 算法 Java
JVM组成结构详解:类加载、运行时数据区、执行引擎与垃圾收集器的协同工作
【8月更文挑战第25天】Java虚拟机(JVM)是Java平台的核心,它使Java程序能在任何支持JVM的平台上运行。JVM包含复杂的结构,如类加载子系统、运行时数据区、执行引擎、本地库接口和垃圾收集器。例如,当运行含有第三方库的程序时,类加载子系统会加载必要的.class文件;运行时数据区管理程序数据,如对象实例存储在堆中;执行引擎执行字节码;本地库接口允许Java调用本地应用程序;垃圾收集器则负责清理不再使用的对象,防止内存泄漏。这些组件协同工作,确保了Java程序的高效运行。
34 3
|
4月前
|
C# UED 开发者
WPF打印功能实现秘籍:从页面到纸张,带你玩转WPF打印技术大揭秘!
【8月更文挑战第31天】在WPF应用开发中,打印功能至关重要,不仅能提升用户体验,还增强了应用的实用性。本文介绍WPF打印的基础概念与实现方法,涵盖页面元素打印、打印机设置及打印预览。通过具体案例,展示了如何利用`PrintDialog`和`PrintDocument`控件添加打印支持,并使用`PrinterSettings`类进行配置,最后通过`PrintPreviewWindow`实现打印预览功能。
485 0
|
4月前
|
C# UED 开发者
WPF动画大揭秘:掌握动画技巧,让你的界面动起来,告别枯燥与乏味!
【8月更文挑战第31天】在WPF应用开发中,动画能显著提升用户体验,使其更加生动有趣。本文将介绍WPF动画的基础知识和实现方法,包括平移、缩放、旋转等常见类型,并通过示例代码展示如何使用`DoubleAnimation`创建平移动画。此外,还将介绍动画触发器的使用,帮助开发者更好地控制动画效果,提升应用的吸引力。
245 0
|
4月前
|
算法 Java 程序员
【JVM的秘密花园】揭秘垃圾收集器的神秘面纱!
【8月更文挑战第25天】在Java虚拟机(JVM)中,垃圾收集(GC)自动管理内存,回收未使用的对象以避免内存泄漏和性能下降。本文深入介绍了JVM中的GC算法,包括串行、并行、CMS及G1等类型及其工作原理。选择合适的GC策略至关重要:小型应用适合串行收集器;大型应用或多核CPU环境推荐并行收集器或CMS;需减少停顿时间时,CMS是好选择;G1适用于大堆且对停顿时间敏感的应用。理解这些能帮助开发者优化程序性能和稳定性。
40 0
|
4月前
|
算法 Java
JVM自动内存管理之垃圾收集器
这篇文章是关于Java虚拟机(JVM)自动内存管理中的垃圾收集器的详细介绍。
|
1月前
|
缓存 Prometheus 监控
Elasticsearch集群JVM调优设置合适的堆内存大小
Elasticsearch集群JVM调优设置合适的堆内存大小
284 1
|
2月前
|
存储 安全 Java
jvm 锁的 膨胀过程?锁内存怎么变化的
【10月更文挑战第3天】在Java虚拟机(JVM)中,`synchronized`关键字用于实现同步,确保多个线程在访问共享资源时的一致性和线程安全。JVM对`synchronized`进行了优化,以适应不同的竞争场景,这种优化主要体现在锁的膨胀过程,即从偏向锁到轻量级锁,再到重量级锁的转变。下面我们将详细介绍这一过程以及锁在内存中的变化。
44 4