实例透彻分析CMS垃圾收集器执行过程
CMS收集器收集步骤:
在上一次【https://www.cnblogs.com/webor2006/p/11055468.html】中已经对CMS的垃圾收集器有了一定的理论上的了解,其中提到了CMS收集器完整的七个步骤,这一次则对每一个步骤进行一个详细了解,并会用程序来理解这七个步骤。
- Phase1 :Initial Mark【初始标记】
这个是CMS两次stop-the-world事件的其中一次,这个阶段的目标是:标记那些直接被GC root引用或被年轻代存活对象所引用的所有对象。用图来表示:
上面有对象是直接被GC ROOTS所指用的,有些对象是被年轻代引用的,都会被标记出来。 - Phase2 : Concurrent Mark 【并发标记】
在这个阶段Garbage Collector会遍历老年代,然后标记所有存活的对象,它会根据上个阶段找到GC ROOTS遍历查找。并发标记阶段,它会与用户的应用程序并发运行。并不是老年代所有的存活对象都会被标记,因为在标记期间用户的程序可能会改变一些引用。如下图:
在上面的图中,与阶段1的图进行对比,就会发现有一个对象的引用已经发生了变化,如标黑的那个对象。
- Phase3 : Concurrent Preclean【并发预先清除】
这也是一个并发阶段,与应用的线程并发运行,并不会stop应用的线程。在并发运行的过程中,一些对象的引用可能会发生变化,但是这种情况发生时,JVM会将包含这个对象的区域(Card)标记为Dirty,这也就是Card Marking。
在pre-clean阶段,那些能够从Dirty对象到达的对象也会被标记,这个标记做完之后,dirty card标记就会被清除了。
下面看下示意图:
上图中标红的则为Dirty,而能够被它所直接到达的对象也会被标记,标记完了则dirty card标记被清除,如下:

- Phase4 : Concurrent Abortable Preclean【并发可能失败的预先清除】
这也是一个并发阶段,但是同样不会影响用户的应用线程,这个阶段是为了尽量承担STW(stop-the-world)中最终标记阶段的工作。这个阶段持续时间依赖于很多的因素,由于这个阶段是在重复做很多相同的工作,直接满足一些条件(比如:重复迭代的次数、完成的工作量或者时钟时间等) - Phase5 : Final Remark【最终重新标记】
这是第二个STW阶段,也是CMS中的最后一个,这个阶段的目标是标记老年代所有的存活对象,由于之前的阶段是并发执行的,GC线程可能跟不上应用程序的变化,为了完成标记老年代所有存活对象的目标,STW就非常有必要了。
通常CMS的Final Remark阶段会在年代代尽可能干净的时候运行,目的是为了减少连续STW发生的可能性(年轻代存活对象过多的话,也会导致老年代涉及的存活对象会很多)。这个阶段会比前面的几个阶段更复杂一些。 - 标记阶段完成
经历过以上五个阶段之后,老年代所有存活的对象都被标记过了,现在可以通过清除算法去清理那些老年代不再使用的对象。可见其实CMS是将一个标记阶段细分成五个子阶段了。 - Phase6 : Concurrent Sweep【并发清除】
这里不需要STW,它是与用户的应用程序并发运行,这个阶段是:清除那些不再使用的对象,回收它们的占用空间为将来使用,如图:
- Phase7 : Concurrent Reset【并发重置】
这个阶段也是并发执行的,它会重设CMS内部的数据结构,为下次的GC做准备。
好,下面来对CMS进行一个总结:CMS通过将大量工作分散到并发处理阶段来减少STW时间,在这块做得非常优秀,但是CMS也有一些其它的问题,主要是如下问题:
1、CMS收集器无法处理浮动垃圾(Floating Garbage),可能出现“Concurrent Mode Failure”失败而导致另一次Full GC的产生,可能引发串行Full GC;
2、空间碎片,导致无法分配大对象,CMS收集器提供了一个-XX:+UseCMSCompactAtFullCollection开发参数(默认就是开启的),用于在CMS收集器顶不住要进行Full GC时开启内存碎片的合并整理过程,内存整理的过程是无法并发的,空间碎片问题没有了,但停顿时间不得不变长;
3、对于堆比较大的应用,GC的时间难以预估。
实践来感受CMS的七大步骤:
关于CMS的七大步骤我们已经理论话的对它进行了学习,但是!!!还是有些抽象,所以接下来会用程序来加深对步骤的理解,可以完完整整通过实验来看到所有的步骤,先新建一个测试类:

目前程序是平淡无奇的,接下来给JVM增加一些启动参数,如下:




好,整个实验需要的JVM参数都已经设定好了,接下来运行看一下输出:
/Library/Java/JavaVirtualMachines/jdk1.8.0_92.jdk/Contents/Home/bin/java -verbose:gc -Xms20M -Xmx20M -Xmn10M -XX:+PrintGCDetails -XX:SurvivorRatio=8 -XX:+UseConcMarkSweepGC -Dfile.encoding=UTF-8 -classpath /Library/Java/JavaVirtualMachines/jdk1.8.0_92.jdk/Contents/Home/jre/lib/charsets.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_92.jdk/Contents/Home/jre/lib/deploy.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_92.jdk/Contents/Home/jre/lib/ext/cldrdata.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_92.jdk/Contents/Home/jre/lib/ext/dnsns.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_92.jdk/Contents/Home/jre/lib/ext/jaccess.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_92.jdk/Contents/Home/jre/lib/ext/jfxrt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_92.jdk/Contents/Home/jre/lib/ext/localedata.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_92.jdk/Contents/Home/jre/lib/ext/nashorn.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_92.jdk/Contents/Home/jre/lib/ext/sunec.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_92.jdk/Contents/Home/jre/lib/ext/sunjce_provider.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_92.jdk/Contents/Home/jre/lib/ext/sunpkcs11.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_92.jdk/Contents/Home/jre/lib/ext/zipfs.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_92.jdk/Contents/Home/jre/lib/javaws.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_92.jdk/Contents/Home/jre/lib/jce.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_92.jdk/Contents/Home/jre/lib/jfr.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_92.jdk/Contents/Home/jre/lib/jfxswt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_92.jdk/Contents/Home/jre/lib/jsse.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_92.jdk/Contents/Home/jre/lib/management-agent.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_92.jdk/Contents/Home/jre/lib/plugin.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_92.jdk/Contents/Home/jre/lib/resources.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_92.jdk/Contents/Home/jre/lib/rt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_92.jdk/Contents/Home/lib/ant-javafx.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_92.jdk/Contents/Home/lib/dt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_92.jdk/Contents/Home/lib/javafx-mx.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_92.jdk/Contents/Home/lib/jconsole.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_92.jdk/Contents/Home/lib/packager.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_92.jdk/Contents/Home/lib/sa-jdi.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_92.jdk/Contents/Home/lib/tools.jar:/Users/xiongwei/Documents/workspace/IntelliJSpace/jvm_lectue/out/production/classes:/Users/xiongwei/.gradle/caches/modules-2/files-2.1/mysql/mysql-connector-java/5.1.34/46deba4adbdb4967367b013cbc67b7f7373da60a/mysql-connector-java-5.1.34.jar:/Users/xiongwei/.gradle/caches/modules-2/files-2.1/cglib/cglib/3.2.0/bced5c83ed985c080a24dc5a42b0ca631556f413/cglib-3.2.0.jar:/Users/xiongwei/.gradle/caches/modules-2/files-2.1/org.ow2.asm/asm/5.0.3/dcc2193db20e19e1feca8b1240dbbc4e190824fa/asm-5.0.3.jar:/Users/xiongwei/.gradle/caches/modules-2/files-2.1/org.apache.ant/ant/1.9.4/6d473e8653d952045f550f4ef225a9591b79094a/ant-1.9.4.jar:/Users/xiongwei/.gradle/caches/modules-2/files-2.1/org.apache.ant/ant-launcher/1.9.4/334b62cb4be0432769679e8b94e83f8fd5ed395c/ant-launcher-1.9.4.jar com.jvm.gc.MyTest5
111111
[GC (Allocation Failure) [ParNew: 5119K->354K(9216K), 0.0038338 secs] 5119K->4452K(19456K), 0.0038874 secs] [Times: user=0.01 sys=0.00, real=0.00 secs]
222222
333333
[GC (Allocation Failure) [ParNew (promotion failed): 6657K->6814K(9216K), 0.0038483 secs][CMS: 8196K->8192K(10240K), 0.0041740 secs] 10755K->10573K(19456K), [Metaspace: 2650K->2650K(1056768K)], 0.0080758 secs] [Times: user=0.01 sys=0.00, real=0.01 secs]
[GC (CMS Initial Mark) [1 CMS-initial-mark: 8192K(10240K)] 14669K(19456K), 0.0005176 secs] [Times: user=0.01 sys=0.00, real=0.00 secs]
[CMS-concurrent-mark-start]
[CMS-concurrent-mark: 0.000/0.000 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
[CMS-concurrent-preclean-start]
444444
[CMS-concurrent-preclean: 0.000/0.000 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
[CMS-concurrent-abortable-preclean-start]
[CMS-concurrent-abortable-preclean: 0.000/0.000 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
[GC (CMS Final Remark) [YG occupancy: 6800 K (9216 K)][Rescan (parallel) , 0.0020690 secs][weak refs processing, 0.0000105 secs][class unloading, 0.0002582 secs][scrub symbol table, 0.0005401 secs][scrub string table, 0.0001471 secs][1 CMS-remark: 8192K(10240K)] 14992K(19456K), 0.0031107 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
[CMS-concurrent-sweep-start]
[CMS-concurrent-sweep: 0.000/0.000 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
[CMS-concurrent-reset-start]
[CMS-concurrent-reset: 0.000/0.000 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
Heap
par new generation total 9216K, used 6964K [0x00000007bec00000, 0x00000007bf600000, 0x00000007bf600000)
eden space 8192K, 85% used [0x00000007bec00000, 0x00000007bf2cd1e0, 0x00000007bf400000)
from space 1024K, 0% used [0x00000007bf400000, 0x00000007bf400000, 0x00000007bf500000)
to space 1024K, 0% used [0x00000007bf500000, 0x00000007bf500000, 0x00000007bf600000)
concurrent mark-sweep generation total 10240K, used 8192K [0x00000007bf600000, 0x00000007c0000000, 0x00000007c0000000)
Metaspace used 2657K, capacity 4486K, committed 4864K, reserved 1056768K
class space used 287K, capacity 386K, committed 512K, reserved 1048576K Process finished with exit code 0
哇~~好神奇,输出了这么多日志,下面咱们来仔细分析一下:




下面具体来分析一下GC的日志:


这不就是七大阶段的第一阶段么?



接下来继续:

这不是对应七大步骤的第二步骤么?


接着第三个阶段:


对应第四个阶段:


接着对应第五个步骤了,执行了一次STW了:

其中这个阶段的日志信息有点多,下面解读一下:






接着继续:

对应第六个阶段:

最后一阶段:


整个CMS垃圾收集器处理完之后,接下来看一下堆的情况:


实例透彻分析CMS垃圾收集器执行过程的更多相关文章
- 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 ...
- Mybatis拦截器执行过程解析
上一篇文章 Mybatis拦截器之数据加密解密 介绍了 Mybatis 拦截器的简单使用,这篇文章将透彻的分析 Mybatis 是怎样发现拦截器以及调用拦截器的 intercept 方法的 小伙伴先按 ...
- CMS垃圾收集器
介绍 CMS垃圾回收器的全称是Concurrent Mark-Sweep Collector,从名字上可以看出两点,一个是使用的是并发收集,第二个是使用的收集算法是Mark-Sweep.从而也可以推测 ...
- 稳了!我准备了1个晚上的CMS垃圾收集器
面试官:今天还是来聊聊CMS垃圾收集器呗? 候选者:嗯啊... 候选者:如果用Seria和Parallel系列的垃圾收集器:在垃圾回收的时,用户线程都会完全停止,直至垃圾回收结束! 候选者:CMS的全 ...
- CMS垃圾收集器——重新标记和浮动垃圾的思考
<深入理解java虚拟机 第二版 JVM高级特性与最佳实践>里面提到 CMS 垃圾收集器. CMS 垃圾收集器的垃圾回收分4个步骤: 初始标记(initial mark) 有 STW 并发 ...
- CMS垃圾收集器与G1收集器
1.CMS收集器 CMS收集器是一种以获取最短回收停顿时间为目标的收集器.基于“标记-清除”算法实现,它的运作过程如下: 1)初始标记 2)并发标记 3)重新标记 4)并发清除 初始标记.从新标记这两 ...
- 《深入理解Java虚拟机》(六)堆内存使用分析,垃圾收集器 GC 日志解读
堆内存使用分析,GC 日志解读 重要的东东 在Java中,对象实例都是在堆上创建.一些类信息,常量,静态变量等存储在方法区.堆和方法区都是线程共享的. GC机制是由JVM提供,用来清理需要清除的对象, ...
- CMS垃圾收集器深入详解
上一次[https://www.cnblogs.com/webor2006/p/11048407.html]对安全点和安全区进行了理论化的了解,接下来继续对CMS进行其它理论的了解,还是纯理论!!坚持 ...
- 详细分析SQL语句逻辑执行过程和相关语法
本文目录: 1.SQL语句的逻辑处理顺序 1.2 各数据库系统的语句逻辑处理顺序 1.2.1 SQL Server和Oracle的逻辑执行顺序 1.2.2 MariaDB的逻辑执行顺序 1.2.3 M ...
随机推荐
- MySQL数据库:数据的概念
基本定义 数据:是数据库总存储的基本对象 定义:描述客观事物的符号记录 种类:数字.文字.图形.图像.声音等 数据库:DB 存储数据的集合 数据库管理系统:DBMS 用户和操作系统之间的一层数据管理软 ...
- Linux第三章-Linux搭建Java环境
本文安装系统是基于 CentOS 7 版本及以上 一.安装JDK 1.先去 Oracle官网 下载Linux1.8的版本以 .tar.gz 为后缀的文件,我这里用的是 jdk-8u181-linux- ...
- 8. java 面向对象
一.面向对象特征 1. 封装 方法就是一种封装 关键字private也是一种封装 封装就是讲一些逻辑细节信息隐藏起来,对于外界不可见:外界只需调用我即可: 一旦使用了private进行修饰,那么本类当 ...
- Luogu P5408 【模板】第一类斯特林数·行
为什么要做这题呢,当然是有用啊qwq 首先我们考虑非常经典的式子: \[x^{\overline{n}}=\sum_i \left[^n_i\right] x^i\] 然后上倍增: \[x^{\ove ...
- python做中学(九)定时器函数的用法
程序中,经常用到这种,就是需要固定时间执行的,或者需要每隔一段时间执行的.这里经常用的就是Timer定时器.Thread 类有一个 Timer子类,该子类可用于控制指定函数在特定时间内执行一次. 可以 ...
- Pull Request找原作者做review
最近对代码库进行了一次全局替换,改了150个左右的文件,发了PR后需要找原作者确认一下,于是写了个工具做git blame,地址在这里 写完发现一个问题,如果只是新增一个函数,没有调用,是应该不用找原 ...
- SqlServer,Oracle,db2,MySql查询表索引
SqlServer1. 查询表索引 SELECT 索引名称=a.name ,表名=c.name ,索引字段名=d.name ,索引字段位置=d.colid ,c.status FROM sysinde ...
- 对并发Map的测试
/** * ConcurrentHashMap效率最高 */ public class MapTest { public static void main(String[] args) throws ...
- Linux中的buff/cache内存
我们用free.top等相关能够查询到当前内存的使用情况的命令时,总会有一个buff/cache让我们很困惑. buffer 即写如磁盘时,先保存到磁盘缓冲区(buffer),然后再写入到磁盘. ca ...
- ef core SoftDelete Multi-tenancy 软删除、多租户实现 Global Query Filters
ef core提供了Global Query Filters特性来实现多租户与软删除,收集了一些实现方法. 最简单的例子时微软官方的特性解释. https://docs.microsoft.com/e ...