1、简介
Concurrent Mark Sweep,是一种以获取最短回收停顿时间为目标的收集器,尤为重视服务的响应速度。算法
CMS是老年代垃圾回收器,基于标记-清除算法实现。新生代默认使用ParNew收集器,基于复制算法安全
2、垃圾回收过程
分为四个步骤进行垃圾回收:初始标记,并发标记,从新标记,并发清除。只有初始标记和从新标记须要停顿。并发
- 初始标记。只是标记一下GC Roots能直接关联到的老年代对象,速度很快。这一阶段会STW
- 并发标记。就是进行GC Roots的Tracing,处理器能够与用户线程一块儿工做。
- 从新标记。为了修正并发标记期间因用户程序继续运做而致使标记产生变更的那一部分对象的标记记录,这个阶段也会触发STW,停顿时间会比初始标记阶段稍长,远比并发时间短。
- 并发清除,处理器能够与用户线程一块儿工做。
可达性分析方法性能
- 经过一系列的称为“GC Roots”的对象做为起始点,从这些节点开始向下搜索,搜索所走过的路径称为“引用链”,当一个对象到GC Roots没有任何引用链相连时,说明这个对象是可回收的。
- Java语言中,可做为GC Roots的对象包括如下几种:虚拟机栈中引用的对象,方法区中类静态属性引用的对象,方法区中常量引用的对象,本地方法栈中引用的对象。
3、垃圾回收触发时机
新生代垃圾回收触发时机:当 eden 区内存没法为一个新对象分配内存时,就会触发 Minor GCspa
老年代垃圾回收触发时机:线程
一、若是没有设置-XX:+UseCMSInitiatingOccupancyOnly,虚拟机会根据收集的数据决定是否触发(建议线上环境带上这个参数,否则会加大问题排查的难度)。
二、老年代使用率达到阈值
CMSInitiatingOccupancyFraction
,默认92%。
三、永久代的使用率达到阈值
CMSInitiatingPermOccupancyFraction
,默认92%,前提是开启
CMSClassUnloadingEnabled
。
四、新生代的晋升担保失败。老年代没有足够的空间来容纳所有的新生代对象或历史平均晋升到老年代的对象,若是不够的话,就提前进行一次老年代的回收,防止下次进行YGC的时候发生晋升失败。
4、垃圾回收如何作到STW
JVM有个叫作“安全点”和“安全区域”的东西,在发生GC时,全部的线程都会执行到“安全点”停下来。
在须要GC的时候,JVM会设置一个标志,当线程执行到安全点的时候会轮询检测这个标志,若是发现须要GC,则线程会本身挂起,直到GC结束才恢复运行。code
可是对于一些没有得到或没法得到CPU时间的线程,就没办法等到它执行到安全点了,因此这个时候只要这个线程是在安全区域的,也能够进行GC,安全区域是一段代码段,在这段代码段中对象的引用关系不会发生变化,因此这个时候进行GC也是安全的。对象
5、关于FullGC
- Full GC == Major GC指的是对老年代/永久代的stop the world的GC
- Full GC的次数 = 老年代GC时 stop the world的次数
- Full GC的时间 = 老年代GC时 stop the world的总时间
- CMS 不等于Full GC,咱们能够看到CMS分为多个阶段,只有stop the world的阶段被计算到了Full GC的次数和时间,而和业务线程并发的GC的次数和时间则不被认为是Full GC。CMS主要能够分为initial mark(stop the world), concurrent mark, remark(stop the world), concurrent sweep几个阶段,其中initial mark和remark会stop the world。
6、CMS缺点
- 垃圾回收时会占用一部分线程,致使系统变慢,总吞吐量会下降。
- 没法处理浮动垃圾,须要预留足够的内存空间给用户线程使用,能够经过 -XX:CMSInitiatingOccupancyFraction 参数控制触发垃圾回收的阈值。
- 若是预留的内存没法知足程序须要,就会出现“Concurrent Mode Failure”失败,这时将启动应急预案,启用Serial Old 进行垃圾回收,停顿时间会变长。因此-XX:CMSInitiatingOccupancyFraction 参数的值设置的过高,会致使频繁“Concurrent Mode Failure”失败,性能反而下降。
- 标记-清理,容易产生内存碎片。-XX:+UseCMSCompactAtFullColletion 开启碎片整理功能,默认开启,-XX:CMSFullGCsBeforeCompaction,控制多少次不压缩的FullGC以后来一次带压缩的
7、常见问题
一、promotion failed – concurrent mode failure
Minor GC后, Survivor空间容纳不了剩余对象,将要放入老年代,老年代有碎片或者不能容纳这些对象,就产生了concurrent mode failure, 而后进行stop-the-world的Serial Old收集器。内存
解决办法:-XX:UseCMSCompactAtFullCollection -XX:CMSFullGCBeforeCompaction=5 或者调大新生代或者Survivor空间ci
二、concurrent mode failure
CMS是和业务线程并发运行的,在执行CMS的过程当中有业务对象须要在老年代直接分配,例如大对象,可是老年代没有足够的空间来分配,因此致使concurrent mode failure, 而后须要进行stop-the-world的Serial Old收集器。
解决办法:+XX:CMSInitiatingOccupancyFraction,调大老年带的空间,+XX:CMSMaxAbortablePrecleanTime
三、碎片整理
-XX:+UseCMSCompactAtFullCollection 强制进行空间碎片整理
CMS 采用标记算法,会产生大量的空间碎片。以上参数就是强制执行一次空间碎片整理,可是空间碎片整理会引起STW。
-XX:+CMSFullGCsBeforeCompaction 配置通过几回的FullGC进行空间碎片整理-XX:+CMSFullGCsBeforeCompaction=10 通过10次FGC后进行空间碎片整理,以下降STW次数