首先是一段GC日志
2020-01-13T16: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]
2020-01-13T16:23:07.321-0200: 64.425: [CMS-concurrent-mark-start]
2020-01-13T16: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]
2020-01-13T16:23:07.357-0200: 64.460: [CMS-concurrent-preclean-start]
2020-01-13T16: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]
2020-01-13T16:23:07.373-0200: 64.476: [CMS-concurrent-abortable-preclean-start]
2020-01-13T16: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]
2020-01-13T16: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]
2020-01-13T16:23:08.458-0200: 65.561: [CMS-concurrent-sweep-start]
2020-01-13T16: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]
2020-01-13T16:23:08.485-0200: 65.589: [CMS-concurrent-reset-start]
2020-01-13T16: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]
从日志中可以看出,CMS分为以下几个阶段:
- CMS Initial Mark:初始标记
- CMS concurrent mark:并发标记
- CMS concurrent preclean:并发预清理
- CMS concurrent abortable preclean:并发可中断的预清理
- CMS Final Remark:最终标记
- CMS concurrent sweep:并发清除
- CMS concurrent reset:并发重置
CMS Initial Mark
初始标记阶段,需要stop-the-world,该阶段的目标:找出所有的GC Roots
,它们通常是一下几类对象:
- Local variables
- Static variables
- Active threads
- JNI References
2020-01-13T16: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]
2020-01-13T16:23:07.321-0200: 64.425
:GC开始的时间CMS Initial Mark
:CMS GC的第一个阶段,Initial Mark10812086K(11901376K)
:老年代当前使用量(老年代空间总可用空间)10887844K(12514816K)
:堆空间当前使用量(堆空间总可用空间)0.0001997 secs
:CMS Initial Mark消耗的时间Times: user=0.00 sys=0.00,real=0.00 secs
:该阶段的总耗时- user:该阶段消耗的CPU时间
- sys:该阶段中系统进行
调用
或者等待
的耗时 - real:user / 并发线程数,即该阶段所消耗的总的时间
CMS concurrent mark
并发标记阶段,不需要stop-the-world,也就是可以和用户线程并行,需要给GC线程分配1/4 cpu cores线程数来执行GC,这个阶段主要的目标:从Initial Mark阶段找出的GC Roots开始,遍历对象图,然后标记出所有的存活对象
2020-01-13T16:23:07.321-0200: 64.425: [CMS-concurrent-mark-start]
2020-01-13T16: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]
CMS concurrent preclean
并发预清理阶段,不需要stop-the-world,由于concurrent mark阶段是和用户线程并发进行的,因此在过程中引用关系很可能会发生改变,有的对象可能已经被JVM标记为dirty
,同时有可能会出现存活的对象没有被标记的情况,为了避免这些情况发生所以有了preclean 阶段,该阶段的主要目标:处理那些在concurrent mark阶段由于用户线程导致引用关系改变的对象
2020-01-13T16:23:07.357-0200: 64.460: [CMS-concurrent-preclean-start]
2020-01-13T16: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]
CMS concurrent abortable preclean
并发可中断的预清理阶段,不需要stop-the-world,跟preclean阶段做的工作差不多,不同的是,这个阶段是可以被中断的,该阶段的目标:减少Final Remark阶段的工作量
2020-01-13T16:23:07.373-0200: 64.476: [CMS-concurrent-abortable-preclean-start]
2020-01-13T16: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]
CMS Final Remark
最终标记阶段,需要stop-the-world,这是CMS中的最后一个需要stop-the-world的阶段,该阶段的目标:标记所有的老年代的存活对象,包括那些在并发标记3个阶段期间发生引用关系变化的存活对象,该阶段通常会在新生代被清空的情况下执行,目的是为了消除多次进行stop-the-world带来的影响
2020-01-13T16: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]
2020-01-13T16:23:08.447-0200: 65.550
:GC开始的时间CMS Final Remark
:CMS 最终标记阶段YG occupancy: 387920 K(613440 K)]
:新生代已使用量(总量)Rescan (parallel), 0.0085125 secs
:标记所有的存活对象,耗时0.0085125secsweak refs processing, 0.0000243 secs
:第一个子阶段,处理弱引用class unloading, 0.0013120 secs
:第二个子阶段,卸载无用的classscrub symbol table, 0.0008345 secs
:最后一个子阶段,清理持有class-level metadata的string tables和一些symbol10812086K(11901376K)
:该阶段结束时老年代已使用量(总量)11200006K(12514816K)
:该阶段结束时堆空间已使用量(总量)0.0110730 secs
:该阶段耗时Times: user=0.06 sys=0.00, real=0.01 secs
:整个阶段耗时
CMS concurrent sweep
并发清除阶段,不需要stop-the-world,该阶段的目标:清理掉垃圾对象
2020-01-13T16:23:08.458-0200: 65.561: [CMS-concurrent-sweep-start]
2020-01-13T16: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]
CMS concurrent reset
并发重置阶段,不需要stop-the-world,该阶段的目标是:重置CMS内部数据结构,为下一次回收做准备
2020-01-13T16:23:08.485-0200: 65.589: [CMS-concurrent-reset-start]
2020-01-13T16: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]