JVM CMS垃圾回收器核心原理(HotSpot)

1. CMS介绍

CMS is a type of GC and is divided into phases。

uyXg3

不像其它的垃圾回收器,CMS不会压缩堆空间。CMS不会移动对象以保证空闲空间的连续性,相反,CMS保存所有空闲内存片段的列表。通过这样的方式,CMS可以避免为存活对象重新分配位置引起的开销(为对象重新分配位置是一个高开销的操作,并且会STW),不过随着堆空间的减少容易引起碎片化。为了减少碎片化的风险,CMS会对对象的size做统计分析,并保存不同size的对象的空闲列表。

 

2. CMS暂停时间

根据前面的分析,CMS有两个phases会引起pause,initial mark与remark。

<1> initial mark

为了标记年老代,这个阶段需要找出所有的root references,有:

  • thread stacks references
  • young space references

通常,thread stacks是可控的,某一应用可认为常量。

那么问题就在于young space了,包括了Eden,S1,S2。通常,在CMS前面已经触发了YGC,这个时候,年轻代空间中只存在存活对象在Survivor空间中,由于survivor空间一般较小,此时scan年轻代references的时间会很短。

但是,如果initial mark开始的时候,Eden是满的,则initial remark将需要花较长的时间,一旦CMS被触发,则应用将会暂停较长时间。

 

<2> remark

大部分的标记过程是与应用并行进行的(concurrent remark phase),不过应用可能在concurrent mark过程中修改对象图。因此,当concurrent mark结束时,垃圾收集器需要暂停应用,再次进行mark以确保所有的可达对象都被标记为存活。

 

 

3. CMS触发的条件

1. 如果应用主动请求full gc,直接触发;

2. 是否设置UseCMSInitiatingOccupancyOnly;

3. 没有设置UseCMSInitiatingOccupancyOnly

  • 统计开启(stats.valid),统计的cms完成时间小于cms剩余空间被填满的时间,则触发;
  • 统计不可用,(第一次没有统计信息,!stats.valid),年老代大于_bootstrap_occupancy,则触发;

4. 设置UseCMSInitiatingOccupancyOnly

  • 根据指定年老代的判断逻辑should_concurrent_collect,true则触发;
  • 根据增量模式收集是否失败,incremental_collection_will_fail,true则触发;
  • 根据元数据区的判断逻辑should_concurrent_collect,true则触发;
  • 最后根据触发间隔(CMSTriggerInterval,默认为-1,所以一般不走这个逻辑);

(代码实现在:gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp)

should_concurrent_collect的逻辑实现

  • 判断occupancy是否大于init_occupancy,大于则触发;
  • 如果设置了UseCMSInitiatingOccupancyOnly,直接返回,不再继续后面逻辑;
  • ……

 

(代码实现在:gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp)

 

 

如果未说明,本Blog中文章皆为原创文章,请尊重他人劳动,转载请注明: 转载自jmatrix

本文链接地址: JVM CMS垃圾回收器核心原理(HotSpot)

(注:一般引用了,我都会添加引用,如果有侵权的请联系我)



This entry was posted in JVM. Bookmark the permalink. Follow any comments here with the RSS feed for this post. Trackbacks are closed, but you can post a comment.