JVM - CMS深度剖析

简介: JVM - CMS深度剖析

20200630113409992.png

Pre


JVM-04垃圾收集Garbage Collection(上)【垃圾对象的判定】

JVM-05垃圾收集Garbage Collection(中)【垃圾收集算法】

JVM-06垃圾收集Garbage Collection(下)【垃圾收集器】

JVM - 再聊GC垃圾收集算法及垃圾收集器


概述


Concurrent Mark Sweep 并发标记清除 。


CMS 收集器是一种以获取最短回收停顿时间为目标的收集器。


它非常符合在注重用户体验的应用上使用,它是HotSpot虚拟机第一款真正意义上的并发收集器,它第一次实现了让垃圾收集线程与用户线程(基本上)同时工作 。


从名字( Mark Sweep )上也可以看出 CMS收集器是一种 “标记-清除”算法实现的垃圾收集器。


阶段

20200630001152719.png


初始标记 (STW)


初始标记阶段,会Stop the word , 这个阶段CMS仅标记被GC Root直接引用的对象,所以速度很快。


为什么这个阶段要STW呢?


试想一下,如果初始标记阶段 GC线程和用户线程同时运行,GC的过程中,用户线程还是会有新的垃圾对象产生 ,那啥时候能标记完,徒增复杂。 同时CMS设计的理念就是用户感知至上,所以虽然STW,但也尽量缩短STW的时间,所以选择了仅标记被GC Root直接引用的对象,而无需遍历整个堆 。


并发标记 (用户线程和GC线程并行工作)


经过了上一步的初始标记, 已经将GC Root 直接引用的对象标记完成。

CMS 老年代的Garbage Collector , 回收的是整个堆的垃圾对象,效率随着堆的大小成反比 ( 如果堆比较大,比如10G,CMS也是有点吃力的,所以才有了G1)


为了避免GC时间过长,这个阶段CMS 让用户线程和 GC线程同时工作,尽量减少用户线程的停顿。 GC线程这个时候就要从GC Roots的直接关联对象开始遍历整个对象图,这个耗时最长。 所以CMS重点优化了这块 。 I


用户线程和GC线程并行工作,多少都会存在一些问题 。因为用户程序继续运行,可能会有导致已经标记过的对象状态发生改变。


试想一下 GC工作的时候,用户线程也在工作


如果GC完成后,当时遍历的用户线程引用的对象由不是垃圾对象,变成了垃圾对象 ,那是不是就 漏标了?

如果GC线程运行中,当时标记的对象是垃圾对象,但是用户线程运行的过程中又把这个对象重新引用了,那是不是 错标了 ?

怎么办呢? CMS设计了 下个阶段 重新标记 来修复这个阶段因对象状态变更导致的标记错误。


重新标记 (STW)


这个阶段主要是修正并发标记期间因为用户程序继续运行而导致标记产生变动的那一部分对象的标记记录。 所以这个时候要STW,不然还是会出现阶段二的情况。


这个阶段的停顿时间一般会比初始标记阶段的时间稍长,远远比并发标记阶段时间短


如何重新标记呢? 这里只要采用 三色标记中的增量更新算法。


并发清理(用户线程和GC线程并行工作)


又是并行执行

如果这个清理阶段又有新的对象进来(肯定没有被标记,因为上一步已经标记过了),这个时候怎么办? 也删掉? 还不是垃圾对象啊 删掉那肯定不行。该怎么办呢?


CMS是这样处理的: 对于新增对象会被标记为黑色不做任何处理


这样的对象被称为 【浮动垃圾】, 标记黑色,本次不处理,等下次GC。


并发重置

经过这么一轮的标记,最后的阶段 肯定是把 标记清除掉,等待下一轮 ~


concurrent mode failure 是怎么回事儿


本身full GC 就是因为老年代没有空间了, 在 并发标记 和 并发清除阶段 是 用户线程和GC线程 并行执行, 如果这个时候 用户线程又产生了一些大对象或者符合条件的对象晋升到了老年代, 这个时候 老年代没有空间存放这些对象了,GC一边回收,系统一边运行,也许没回收完就再次触发full gc , 就出现了 “concurrent mode failure” .


出现这个情况,CMS是怎么处理呢? 直接OOM?


显然不是,CMS会Stop the word , 然后使用Serial Old 单线程 来进行垃圾回收。 尽量避免这种情况,效率非常低。


如何避免呢? 可以合理设置CMS的参数 (-XX:CMSInitiatingOccupancyFraction) 默认92% ,可以将这个值设置为80%(根据业务考量该值,你的系统大对象多的话 ,当然了,你设置了 80% 就意味着你老年代将会有20%的空间不可用,这部分空间仅能用来存放GC过程中新的对象,需要合理评估),尽量避免并发失败的情况的发生。


CMS核心参数


-XX:+UseConcMarkSweepGC:启用cms

-XX:ConcGCThreads:并发的GC线程数

-XX:+UseCMSCompactAtFullCollection:FullGC之后做压缩整理,其目的是为了减少内存碎片

-XX:CMSFullGCsBeforeCompaction:多少次FullGC之后压缩一次,默认是0,代表每次FullGC后都会压缩一次

-XX:CMSInitiatingOccupancyFraction: 当老年代使用达到该比例时会触发FullGC(默认是92%)

-XX:+UseCMSInitiatingOccupancyOnly:只使用设定的回收阈值(-XX:CMSInitiatingOccupancyFraction设定的值),如果不指定,JVM仅在第一次使用设定值,后续则会自动调整

-XX:+CMSScavengeBeforeRemark:在CMS GC前启动一次minor gc,目的在于减少老年代对年轻代的引用,降低CMS GC的标记阶段时的开销,一般CMS的GC耗时 80%都在标记阶段

-XX:+CMSParallellnitialMarkEnabled:表示在初始标记的时候多线程执行,缩短STW的时间

-XX:+CMSParallelRemarkEnabled:在重新标记的时候多线程执行,缩短STW的时间


CMS的优缺点

优点

  1. 并发收集
  2. 低停顿 ,用户体验至上

缺点:

  1. 用户线程和GC线程有可能争抢CPU资源
  2. 无法处理浮动垃圾 , 在并发标记和并发清理阶段又产生垃圾,这种浮动垃圾只能等到下一次gc再清理了
  3. 回收算法-“标记-清除”算法会导致收集结束时会有大量空间碎片产生, 可以通过参数-XX:+UseCMSCompactAtFullCollection让jvm在执行完标记清除后再做整理,从而实现“标记-整理”的效果,减少内存碎片。 还有个参数 -XX:CMSFullGCsBeforeCompaction 代表多少次Full GC以后整理一下内存碎片,默认为0 即每次Full GC之后都会整理内存碎片。
  4. 执行过程中的不确定性,会存在上一次垃圾回收还没执行完,然后垃圾回收又被触发的情况 。 比如在并发标记和并发清理阶段会出现concurrent mode failure,这个时候会STW,会切换到Serial Old ,效率非常低。


ParNew + CMS设置Demo


-Xms3072M -Xmx3072M -Xmn2048M -Xss1M  -XX:MetaspaceSize=256M -XX:MaxMetaspaceSize=256M


没有标准答案,需要依据自己的业务特点,进行合理的参数调优。


GC算法底层实现

三色标记


在并发标记的过程中,应用线程也在运行,所以GC线程在运行期间应用线程使用的对象之间的引用可能发生变化,会存在多标和漏标的现象。


JVM把Gcroots可达性分析遍历对象过程中遇到的对象, 按照“是否访问过”这个条件标记成以下三种颜色 : 黑 灰 白


黑色: 表示对象已经被垃圾收集器访问过, 且这个对象的所有引用都已经扫描过。 黑色的对象代表已经扫描过, 它是安全存活的, 如果有其他对象引用指向了黑色对象, 无须重新扫描一遍。 黑色对象不可能直接(不经过灰色对象) 指向某个白色对象。


灰色: 表示对象已经被垃圾收集器访问过, 但这个对象上至少存在一个引用还没有被扫描过。


白色: 表示对象尚未被垃圾收集器访问过。 显然在可达性分析刚刚开始的阶段, 所有的对象都是白色的, 若在分析结束的阶段, 仍然是白色的对象, 即代表不可达。

相关文章
|
6月前
|
算法 Java
jvm性能调优 - 15JVM的老年代垃圾回收器CMS的缺点
jvm性能调优 - 15JVM的老年代垃圾回收器CMS的缺点
116 0
|
6月前
|
消息中间件 算法 Java
jvm性能调优 - 14JVM的老年代垃圾回收器CMS原理
jvm性能调优 - 14JVM的老年代垃圾回收器CMS原理
85 0
|
存储 缓存 算法
JVM第三讲:深入理解java虚拟机之垃圾回收算法?CMS垃圾回收的基本流程?对象引用类型?
JVM第三讲:深入理解java虚拟机之垃圾回收算法?CMS垃圾回收的基本流程?对象引用类型?
223 0
|
22天前
|
缓存 算法 Java
JVM知识体系学习六:JVM垃圾是什么、GC常用垃圾清除算法、堆内存逻辑分区、栈上分配、对象何时进入老年代、有关老年代新生代的两个问题、常见的垃圾回收器、CMS
这篇文章详细介绍了Java虚拟机(JVM)中的垃圾回收机制,包括垃圾的定义、垃圾回收算法、堆内存的逻辑分区、对象的内存分配和回收过程,以及不同垃圾回收器的工作原理和参数设置。
45 4
JVM知识体系学习六:JVM垃圾是什么、GC常用垃圾清除算法、堆内存逻辑分区、栈上分配、对象何时进入老年代、有关老年代新生代的两个问题、常见的垃圾回收器、CMS
|
18天前
|
Java
JVM进阶调优系列(5)CMS回收器通俗演义一文讲透FullGC
本文介绍了JVM中CMS垃圾回收器对Full GC的优化,包括Stop the world的影响、Full GC触发条件、GC过程的四个阶段(初始标记、并发标记、重新标记、并发清理)及并发清理期间的Concurrent mode failure处理,并简述了GC roots的概念及其在GC中的作用。
|
4月前
|
算法 安全 Java
(七)JVM成神路之GC分代篇:分代GC器、CMS收集器及YoungGC、FullGC日志剖析
在《GC基础篇》中曾谈到过分代以及分区回收的概念,但基础篇更多的是建立在GC的一些算法理论上进行高谈阔论,而本篇则重点会对于分代收集器的实现进行全面详解,其中会涵盖串行收集器、并行收集器、三色标记、SATB算法、GC执行过程、并发标记、CMS收集器等知识,本篇则偏重于分析GC机制的落地实现,也就是垃圾收集器(Garbage Collector)。
103 8
|
6月前
|
存储 算法 Java
深入浅出JVM(十七)之并发垃圾收集器CMS
深入浅出JVM(十七)之并发垃圾收集器CMS
|
6月前
|
运维 监控 Java
【深入浅出JVM原理及调优】「搭建理论知识框架」全方位带你深度剖析Java线程转储分析的开发指南
学习JVM需要一定的编程经验和计算机基础知识,适用于从事Java开发、系统架构设计、性能优化、研究学习等领域的专业人士和技术爱好者。
101 5
【深入浅出JVM原理及调优】「搭建理论知识框架」全方位带你深度剖析Java线程转储分析的开发指南
|
12月前
|
缓存 算法 Java
JVM CMS GC算法解析
JVM CMS GC算法解析
77 0
|
前端开发 Java
Java虚拟机 CMS GC 调优解析
随着 JDK 版本的不断升级,其 GC 策略也随之不停革新,从早期的 1.4 到如今的 11(本文仅讨论在线上环境落地规模较大的版本),其对应的 GC 策略也随之由 Serial、Parallel、CMS 演进至当前的 G1 甚至即将落地的 ZGC 。每一次的调整无不是基于环境的适配性以及业务场景特性,无论如何,只要能够基于特定的操作系统内核、物理内存、JDK版本以及业务特性,达到收益最大化,采用何种实现策略都不为过。当然,还是建议大家以官方的推荐为准,基于自己的业务场景进行不断优化调整,这样才能保证万无一失,使得我们的业务能够健康发展。
160 0