jdk9以后官方就推荐使用G1收集器来替代CMS了
CMS和G1区别
CMS | G1 | |
---|---|---|
作用范围 | 老年代 | 整个堆 |
基本概念 | 将老年代分为一个个cardTable,用于并发标记的时候标记那些对象引用变化的table | 把堆区分成一个个region |
区域划分 | 严格划分新生代(edan区,survivor区),老年代,区域之间大小比较固定,物理上是连续的 | 仍然有老年代,新生代概念,每个region都能灵活的扮演Eden空间、Survivor空间,或者老年代空间,以此来灵活变动不同区的大小,物理上他们不是连续的 |
回收目标 | 尽量减少用户线程停顿,region之间采用标记-清理 算法,整体上是标记-整理 ,为了追求效率在清理后不整理,所以会有浮动碎片 | 以用户期望的可预测的停顿时间,按回收的性价比来指定回收计划,采用复制算法 ,将要回收的region存货对象复制到空region,所以一定程度上减少了浮动碎片垃圾的产生,或者说连续空间更多 |
三色标记漏标处理 (见下文) | 增量更新 | 快照拷贝 |
优点 | stw时间短 | 碎片少、停顿时间可控 |
缺点 | 产生内存碎片、cpu资源敏感(并发阶段会抢占cpu资源) | 由于内存是一个个region管理,为了提高minorGC时的效率(避免扫描老年代),用Remembered Set来记录其他,相比cms更占用内存 |
三色标记-漏标
三色标记法将对象的颜色分为了黑、灰、白,三种颜色
- 黑 已扫描对象引用关系,且该对象的属性也被扫描
- 灰 仅扫描了对象引用关系
- 白 尚未扫描(或扫描不到,可被回收的垃圾)
浮动垃圾: 在并发标记过程中,用户线程导致对象引用关系一直在变化。当一个已经被标记颜色的对象,变成了垃圾,由于已经被标记过所以不会被回收。
漏标: 在标记过程中,某个尚未被扫描的白色对象,从灰色对象断开了,又被黑色对象引用了。那在重新标记的阶段,黑色被认为已经扫描过,而灰色的连接也断开了,导致这个白色的对象本应该保留的对象被当成垃圾给回收了
CMS和G1解决这个问题的方法不同
- cms:采用
增量更新
法,从新增引用入手,即如图黑色的B增加了白色的E引用后,在重新标记remark阶段修改B为灰色,重新再扫描一次(效率下降) - g1:采用
原始快照
法,从删除引用入手,即灰色的C断开E的链接时,仍然保留C-E的链接快照。但是这样会把这个过程中正常断开的引用(无黑色引用)垃圾也保留下来了,空间换时间