垃圾收集器ParNew&CMS与底层三色标记算法详解
2023-01-29 23:06:50 11 举报
垃圾收集器ParNew&CMS与底层三色标记算法详解
作者其他创作
大纲/内容
垃圾收集算法
分代收集理论
根据对象的存活周期将内存分为几块,jvm中分为新生代和老年代
标记复制算法
讲内存分为大小相等的两块,其中一块的内存满了,复制到另一半内存,回收另一半
标记整理算法(适合老年代)
标记之后不是直接回收对象,而是讲所有存活的对象向一段移动,清除掉边界以外的内存
标记清除算法(适合年轻代)
标记存活的对象,回收未标记对象,是最基础的收集算法
存在问题
效率问题:标记的对象太多,效率不高
空间问题 :标记后会产生大量不连续的碎片
垃圾收集器
没有万能的垃圾收集器,根据应用场景选择适合自己的垃圾收集
Serial收集器(-XX:+UseSerialGC -XX:+UseSerialOldGC)
串行收集器,最基本的垃圾收集器,进行垃圾收集工作时会STW
新生代采用复制算法UseSerialGC
老年代采用标记-整理算法UseSerialOld
优点
没有线程交互的开销,可以获得很高的单线程收集效率
作为CMS收集器的后备方案
Parallel Scavenge收集器(-XX:+UseParallelGC(年轻代),-XX:+UseParallelOldGC(老年代))
是serial的多线程版本,在垃圾收集时使用多线程,减少STW时间,默认线程数和cpu核数相同,可以用参数修改,不推荐
新生代采用复制算法
老年代采用标记-整理算法
JDK8默认的新生代和老年代收集器:Parallel Scavenge收集器和Parallel Old收集器
ParNew收集器(-XX:+UseParNewGC)
新生代采用复制算法
老年代采用标记-整理算法
和Parallel收集器区别:
可以和CMS收集器配合使用
CMS(Concurrent Mark Sweep)收集器(-XX:+UseConcMarkSweepGC(old))
第一个实现让垃圾收集线程和用户线程同时工作的垃圾收集器
老年代使用标记-清除算法
运作过程:
初始标记:
暂停所有的其他线程(STW),并记录下GC root直接能引用的对象,速度很快
并发标记:
从GC root直接关联对象向下遍历对象,可以和用户线程一起并发运行
重新标记:
修正并发标记期间,产生变动的那一部分对象的标记记录,三色标记中的增量更新算法
并发清理:
开启用户线程,同时开始GC清理没有被标记的区域
并发重置:
重置本次GC中标记的数据
CMS优点:
并发收集,低停顿
CMS缺点:
对CPU资源敏感(会和服务抢资源)
解决方案: 无
无法处理浮动垃圾(在并发标记和并发清理阶段又产生垃圾,这种浮动垃圾只能等到下一次gc再清理了);
解决方案:无
标记-清除算法会产生大量的碎片
解决方案:然通过参数-XX:+UseCMSCompactAtFullCollection可以让jvm在执行完标记清除后再做整理
执行过程中可能一边回收,一边再次触发full gc, 也就是"concurrentmode failure",此时会进入stop the world,用serial old垃圾收集器来回收
CMS的核心参数:
-XX:+UseConcMarkSweepGC:启用cms
-XX:ConcGCThreads:并发的GC线程数
-XX:+UseCMSCompactAtFullCollection:FullGC之后做压缩整理(减少碎片)
-XX:CMSFullGCsBeforeCompaction:多少次FullGC之后压缩一次,默认是0,代表每次FullGC后都会压缩一次
-XX:CMSInitiatingOccupancyFraction: 当老年代使用达到该比例时会触发FullGC(默认是92,这是百分比)
-XX:+UseCMSInitiatingOccupancyOnly:只使用设定的回收阈值(-XX:CMSInitiatingOccupancyFraction设
定的值),如果不指定,JVM仅在第一次使用设定值,后续则会自动调整
定的值),如果不指定,JVM仅在第一次使用设定值,后续则会自动调整
-XX:+CMSScavengeBeforeRemark:在CMS GC前启动一次minor gc,目的在于减少老年代对年轻代的引
用,降低CMS GC的标记阶段时的开销,一般CMS的GC耗时 80%都在标记阶段
用,降低CMS GC的标记阶段时的开销,一般CMS的GC耗时 80%都在标记阶段
-XX:+CMSParallellnitialMarkEnabled:表示在初始标记的时候多线程执行,缩短STW
-XX:+CMSParallelRemarkEnabled:在重新标记的时候多线程执行,缩短STW;
垃圾收集底层算法
三色标记
在并发标记的过程中,因为标记期间应用线程还在继续跑,对象间的引用可能发生变化,多标和漏标的情况就有可能发生。这里我们引入“三色标记”来给大家解释下,把Gcroots可达性分析遍历对象过程中遇到的对象, 按照“是否访问过”这个条件标记成以下三种颜色:
黑色
表示对象已经被垃圾收集器访问过, 且这个对象的所有引用都已经扫描过
灰色
表示对象已经被垃圾收集器访问过, 但这个对象上至少存在一个引用还没有被扫描过。
白色
表示对象尚未被垃圾收集器访问过
多标会产生浮动垃圾
解决方案:
针对并发标记(还有并发清理)开始后产生的新对象,通常的做法是直接全部当成黑色
漏标会导致被引用的对象被当成垃圾误删除
解决方案:都是虚拟机通过写屏障来实现
增量更新(IncrementalUpdate)CMS用 引用赋值操作前
黑色对象一旦新插入了指向白色对象的引用之后, 它就变回灰色对象了,重新标记时会扫描新增的引用
原始快照(Snapshot At The Beginning,SATB)G1用 引用赋值操作后
当灰色对象要删除指向白色对象的引用关系时, 就将这个要删除的引用记录下来,并发扫描后将白色对象直接标记为黑色对象
为什么G1用SATB?CMS用增量更新?
SATB相对增量更新效率会高(当然SATB可能造成更多的浮动垃圾),因为不需要在重新标记阶段再次深度扫描
被删除引用对象,而CMS对增量引用的根对象会做深度扫描,G1因为很多对象都位于不同的region,CMS就一块老年代区域,重新深度扫描对象的话G1的代价会比CMS高,所以G1选择SATB不深度扫描对象,只是简单标记,等到下一轮GC再深度扫描。
被删除引用对象,而CMS对增量引用的根对象会做深度扫描,G1因为很多对象都位于不同的region,CMS就一块老年代区域,重新深度扫描对象的话G1的代价会比CMS高,所以G1选择SATB不深度扫描对象,只是简单标记,等到下一轮GC再深度扫描。
0 条评论
下一页