CMS全称 ConcurrentMarkSweep,是一款并发的、使用标记-清除算法的垃圾回收器, 如果老年代使用CMS垃圾回收器,需要添加虚拟机参数-“XX:+UseConcMarkSweepGC”
缺点:
1.CMS收集器对CPU资源非常敏感,在并发阶段,它虽然不会导致用户线程停顿,但是由于占用了一部分线程,所以会导致应用程序变慢,总吞吐量降低。CMS默认启动的回收线程数是(cpu数量+3)/4。2.CMS收集器无法处理浮动垃圾,可能出现“Concurrent Mode Failure”失败而导致一次Full GC。在JDK1.6中,CMS收集器当老年代使用了92%的空间后才会进行收集,所以如果CMS运行期间预留的内存无法满足程序需要,就会出现一次“Concurrent Mode Failure”。通过-XX:CMSInitiatingOccupancyFraction可以调整百分比。该参数必须配合UseCMSInitiatingOccupancyOnly使用才有效3.CMS由于是基于标记-清除算法实现的收集器,所以就可能会在收集结束的时候产生大量空间碎片。如果老年代中没有足够大的连续空间来分配当前对象,那么就会可能提前触发Full GC并进行碎片整理
初始化标记(CMS Initial Mark)的日志打印如下:
2019-04-11T16:30:48.164+0800: 14.035: [GC (CMS Initial Mark) [1 CMS-initial-mark: 0K(699072K)] 33843K(1013632K), 0.0066881 secs] [Times: user=0.09 sys=0.00, real=0.01 secs]整个过程会STW。标记GC Roots可达的老年代对象;遍历新生代对象,标记可达的老年代对象;
并发标记(CMS-concurrent-mark)的日志打印如下:
2019-04-11T16:30:48.179+0800: 14.044: [CMS-concurrent-mark-start]
2019-04-11T16:30:48.179+0800: 14.044: [CMS-concurrent-mark: 0.000/0.000 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]该阶段GC线程和应用线程并发执行,遍历InitialMarking阶段标记出来的存活对象,然后继续递归标记这些对象可达的对象。
预处理(CMS-concurrent-preclean)的日志打印如下:
2019-04-11T16:30:48.179+0800: 14.044: [CMS-concurrent-preclean-start]
2019-04-11T16:30:48.179+0800: 14.047: [CMS-concurrent-preclean: 0.003/0.003 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]处理新生代已经发现的引用,比如在并发阶段,在Eden区中分配了一个A对象,A对象引用了一个老年代对象B(这个B之前没有被标记),在这个阶段就会标记对象B为活跃对象。
可中断的预清理(CMS-concurrent-abortable)的日志打印如下:
2019-04-11T16:30:48.179+0800: 14.047: [CMS-concurrent-abortable-preclean-start]
2019-04-11T16:30:52.428+0800: 18.302: [CMS-concurrent-abortable-preclean: 2.860/4.254 secs] [Times: user=9.47 sys=1.09, real=4.25 secs]该阶段发生的前提是,新生代Eden区的内存使用量大于参数 CMSScheduleRemarkEdenSizeThreshold 默认是2M,如果新生代的对象太少,就没有必要执行该阶段,直接执行重新标记阶段。因为CMS GC的终极目标是降低垃圾回收时的暂停时间,所以在该阶段要尽最大的努力去处理那些在并发阶段被应用线程更新的老年代对象,这样在暂停的重新标记阶段就可以少处理一些,暂停时间也会相应的降低。
重新标记(CMS Final Remark)的日志打印如下:
2019-04-11T16:30:52.428+0800: 18.302: [GC (CMS Final Remark) [YG occupancy: 203965 K (314560 K)]2019-04-11T16:30:52.428+0800: 18.303: [Rescan (parallel) , 0.0177423 secs]2019-04-11T16:30:52.447+0800: 18.320: [weak refs processing, 0.0001500 secs]2019-04-11T16:30:52.447+0800: 18.320: [class unloading, 0.0287879 secs]2019-04-11T16:30:52.475+0800: 18.349: [scrub symbol table, 0.0121125 secs]2019-04-11T16:30:52.497+0800: 18.362: [scrub string table, 0.0012159 secs][1 CMS-remark: 0K(699072K)] 203965K(1013632K), 0.0623200 secs] [Times: user=0.13 sys=0.00, real=0.07 secs]并发重新标记,STW过程。遍历新生代对象,重新标记根据GC Roots,重新标记。
并发清理(CMS Concurrent Sweep)的日志打印如下:
[CMS-concurrent-sweep-start]
[CMS-concurrent-sweep: 0.007/0.007 secs] [Times: user=0.00 sys=0.00, real=0.01 secs]并发重置(CMS Concurrent Reset)的日志打印如下:
[CMS-concurrent-reset-start]
[CMS-concurrent-reset: 0.002/0.002 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]