Concurrent Mark and Sweep
优点:大量的工作听过并发线程处理,不需要stop-the-world
缺点:老年代碎片多且在某些情况下暂停时间不可预测,特别是大型堆栈。
启用参数:
-XX:+UseConcMarkSweepGC
主要目的是:
减少GC时间,因为要抢占多大多数的cpu时间或全部cpu时间,所以应用的吞吐量相对于在Parallel GC会小。
并发标记清除算法:在Young Generation使用的是并行mark-copy且stop-the-world算法;在Old Generation使用的是大多数的并发mark-sweep算法。为了防止长时间的暂停在Old Generation:第一、不压缩而是使用free-list管理空闲空间;第二、并发执行mark-sweep,不会stop-the-world,但也是会与应用竞争CPU时间;
默认执行并发垃圾收集的线程数为 ( 并行垃圾收集线程数 + 3 )/ 4
并发线程数量
-XX:+ConcGCThreads=
启用并发标记清除算法
-XX:+UseConcMarkSweepGC
查看线程的核数命令:
java -XX:+PrintFlagsFinal -version | grep ParallelGCThreads
Full GC
2015-05-26T16:23:07.321-0200: 64.425: [GC (CMS Initial Mark) [1 CMS-initial-mark: 10812086K(11901376K)] 10887844K(12514816K), 0.0001997 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 2015-05-26T16:23:07.321-0200: 64.425: [CMS-concurrent-mark-start] 2015-05-26T16:23:07.357-0200: 64.460: [CMS-concurrent-mark: 0.035/0.035 secs] [Times: user=0.07 sys=0.00, real=0.03 secs] 2015-05-26T16:23:07.357-0200: 64.460: [CMS-concurrent-preclean-start] 2015-05-26T16:23:07.373-0200: 64.476: [CMS-concurrent-preclean: 0.016/0.016 secs] [Times: user=0.02 sys=0.00, real=0.02 secs] 2015-05-26T16:23:07.373-0200: 64.476: [CMS-concurrent-abortable-preclean-start] 2015-05-26T16:23:08.446-0200: 65.550: [CMS-concurrent-abortable-preclean: 0.167/1.074 secs] [Times: user=0.20 sys=0.00, real=1.07 secs] 2015-05-26T16:23:08.447-0200: 65.550: [GC (CMS Final Remark) [YG occupancy: 387920 K (613440 K)]65.550: [Rescan (parallel) , 0.0085125 secs]65.559: [weak refs processing, 0.0000243 secs]65.559: [class unloading, 0.0013120 secs]65.560: [scrub symbol table, 0.0008345 secs]65.561: [scrub string table, 0.0001759 secs][1 CMS-remark: 10812086K(11901376K)] 11200006K(12514816K), 0.0110730 secs] [Times: user=0.06 sys=0.00, real=0.01 secs] 2015-05-26T16:23:08.458-0200: 65.561: [CMS-concurrent-sweep-start] 2015-05-26T16:23:08.485-0200: 65.588: [CMS-concurrent-sweep: 0.027/0.027 secs] [Times: user=0.03 sys=0.00, real=0.03 secs] 2015-05-26T16:23:08.485-0200: 65.589: [CMS-concurrent-reset-start] 2015-05-26T16:23:08.497-0200: 65.601: [CMS-concurrent-reset: 0.012/0.012 secs] [Times: user=0.01 sys=0.00, real=0.01 secs]
注意:年轻代Minor GC 可以与老年代并发标记清除收集器一同工作
CMS的Full GC包括7个阶段,1-5是标记阶段,会有两次stop-the-world(Initial Mark 和 Final Remark)
1:GC触发的时钟时间和相对于JVM启动的时间
2:区分GC所处阶段,CMS Initial Mark表示初始标记,标记所有Old Generation中的GC Roots
3:老年代对象数据占用的空间大小
4:老年代总的空间大小
5:堆已使用的空间大小
6:堆总的空间大小
7:初始标记的持续时间
-user:占用CPU的时间长短
-sys:花费在系统调用或等待系统事件的时间长短
-real:应用挂起的时间长短
2020-12-14T09:13:05.211-0800: 1.425: [GC (CMS Initial Mark) [1 CMS-initial-mark: 4983K(118784K)] 12084K(210944K), 0.0006673 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
2020-12-14T09:13:05.211-0800: 1.426: [CMS-concurrent-mark-start]
2020-12-14T09:13:05.216-0800: 1.430: [CMS-concurrent-mark: 0.004/0.004 secs] [Times: user=0.03 sys=0.00, real=0.00 secs]
1:CMS-concurrent-mark:收集器执行阶段,从GC Roots遍历所有老年代对象并标记存活对象(不是所有的存活对象都会别标记,因为没有stop-the-world,应用任然可以改变对象引用)
2:并发标记占用0.35的CPU时间,0.035s的挂钟时间(从事件从开始运行到结束,时钟走过的时间,这其中包含了进程在阻塞和等待状态的时间 (挂钟时间 = 阻塞时间 + 就绪时间 +运行时间))
3:Times在并发标记中基本上无意义,因为它是从CMS-concurrent-mark-start开始,并且包含有除并发标记以外的时间消耗。
Phase 3: Concurrent Preclean
扩展阅读(https://blog.csdn.net/enemyisgodlike/article/details/106960687)
不会stop-the-world,对card区域的dirty对象进行处理,并将从dirty对象可达的对象进行mark;除此之外还会做必要的对象清除和为Final Remark做准备。在本阶段,会查找前一阶段执行过程中,从新生代晋升或新分配或被更新的对象。通过并发地重新扫描这些对象,预清理阶段可以减少下一个stop-the-world 重新标记阶段的工作量。
2020-12-14T09:13:07.918-0800: 4.132: [CMS-concurrent-preclean-start]
2020-12-14T09:13:07.919-0800: 4.133: [CMS-concurrent-preclean: 0.001/0.001 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
1:标识concurrent-preclean阶段
2:并发预清理占用0.016的CPU时间,0.016s的挂钟时间(从事件从开始运行到结束,时钟走过的时间,这其中包含了进程在阻塞和等待状态的时间 (挂钟时间 = 阻塞时间 + 就绪时间 +运行时间))
3:无意义,因为是从并发标记阶段开始计时的。
Phase 4: Concurrent Abortable Preclean.
-XX:CMSScheduleRemarkEdenSizeThreshold=2097152Bytes(2M):当Eden
不会stop-the-world,尽可能与stop-the-world的Final Remark独立开,因为这个阶段需要重复地做一些事情直到达到某个条件停止,执行时间取决于多种因素(迭代次数、做的有效工作量的数量、挂钟时间等);增加这一阶段是为了让我们可以控制这个阶段的结束时机,比如扫描多长时间(默认5秒)或者Eden区使用占比达到期望比例(默认50%)就结束本阶段。
2020-12-14T09:13:07.919-0800: 4.133: [CMS-concurrent-abortable-preclean-start]
2020-12-14T09:13:08.067-0800: 4.281: [CMS-concurrent-abortable-preclean: 0.148/0.148 secs] [Times: user=0.30 sys=0.02, real=0.15 secs]
1:区分并发标记清除垃圾收集执行阶段,这里是concurrent-abortable-preclean阶段
2:并发可中止的预清理阶段,占用0.167的CPU时间,1.074s的挂钟时间(从事件从开始运行到结束,时钟走过的时间,这其中包含了进程在阻塞和等待状态的时间 (挂钟时间 = 阻塞时间 + 就绪时间 +运行时间))
3:无意义,因为是从并发标记阶段开始计时的。
Phase 5: Final Remark
第二个会stop-the-world的阶段,最后标记在老年代所有存活的对象;为了避免多个stop-the-world的收集器连续执行,CMS尽可能在Young Generation为0k的时候执行Final Remark;
2020-12-14T09:13:05.423-0800: 1.638: [GC (CMS Final Remark) [YG occupancy: 47292 K (92160 K)]2020-12-14T09:13:05.423-0800: 1.638: [Rescan (parallel) , 0.0098615 secs]2020-12-14T09:13:05.433-0800: 1.648: [weak refs processing, 0.0000618 secs]2020-12-14T09:13:05.433-0800: 1.648: [class unloading, 0.0023545 secs]2020-12-14T09:13:05.436-0800: 1.650: [scrub symbol table, 0.0024580 secs]2020-12-14T09:13:05.438-0800: 1.653: [scrub string table, 0.0003786 secs][1 CMS-remark: 4983K(118784K)] 52275K(210944K), 0.0155274 secs] [Times: user=0.10 sys=0.00, real=0.01 secs]
1:GC事件触发时间
2:GC事件类型:CMS Final Remark 这里表示CMS的最终标记过程,会标记在Old Generation所有存活的对象(包括在前几个标记阶段创建或修改的对象引用)
3:YG occupancy:当前年轻代对象数据占用空间大小和总的空间大小
4:Rescan(parallel):当应用挂起时,rescan并行地扫描所有的老年代中存活的对象,这里表明是并行执行并且花费了0.0085125秒
5:weak refs processing:最终标记阶段的子阶段是处理弱引用,花费的时间以及相对于JVM启动时间的时间戳
6:class unloading:卸载未使用的类,带有花费的时间和相对于JVM启动时间的时间戳
7:scrub symbol table:清理符号表以及其花费的时间
-scrub string table:清理字符表(类级别的元数据和内部化字符串)及其花费的时间
8:CMS-remark:老年代存储对象占用空间大小和老年代当前的总共大小
9:这一GC阶段前后堆的对象数据占用空间大小以及堆的总空间大小
10:这一GC阶段的花费的时间
11: -user:cup占用时间 -sys:花费在系统调用或等待系统事件的时间
注意:到此,总共的CMS的五个标记阶段已完成
Phase 6: Concurrent Sweep
不会stop-the-world,这一阶段的主要目的是清除垃圾对象并回收垃圾对象占用的内存空间以备以后使用。
1:CMS-concurrent-sweep:清理未标记的对象并回收内存空间
2:对应的cpu占用时间和这一阶段的挂钟时间
3:无意义,记录的是从CMS标记开始至今的时间,远超过这一阶段花费的时间。
Phase 7: Concurrent Reset
并发重置,重置CMS算法内部的数据结构,为下一CMS周期做准备
2020-12-14T09:13:08.096-0800: 4.310: [CMS-concurrent-reset-start]
2020-12-14T09:13:08.096-0800: 4.310: [CMS-concurrent-reset: 0.000/0.000 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
1:区分CMS阶段的标志
2:这一阶段占用CPU的时间和挂钟时间
3:无意义,记录的是从CMS标记开始至今的时间,远超过这一阶段花费的时间。