垃圾收集算法
- 复制算法
- 标记整理算法
- 标记清除算法
分代收集理论:根据年轻代和老年代的内存特点采用不同的收集算法
垃圾收集器
-
Serial串行收集器(年轻代和老年代都可以用,现在几乎不用)
-XX:+UseSerialGC -XX:+UseSerialOldGC
年轻代采用复制算法,老年代采用标记整理算法
STW的时候单线程收集 -
Parallel并行收集器(年轻代和老年代都可以用)
-XX:+UseParallelGC -XX:+UseParallelOldGC
STW的时候多线程收集
可以使用-XX:ParallelGCThreads指定线程数,但是一般不推荐修改
年轻代采用复制算法,老年代采用标记整理算法 -
ParNew(年轻代使用)
-XX:+UseParNewGC
年轻代采用复制算法,老年代采用标记整理算法
和Parallel收集器类似也是多线程收集,区别在于可以和CMS收集器配合使用 -
CMS收集器(老年代使用)
-XX:+UseConcMarkSweepGC
标记清除算法
步骤:
初始标记:先STW并记录下GCRoots能直接引用的对象,速度很快
并发标记:从GCRoots的直接关联对象开始遍历整个对象图的过程,耗时较长但是不需要停顿用户线程
重新标记:会STW,修正并发标记期间因为程序运行导致标记产生变动的那一部分对象及标记记录。这个阶段停顿时间会比初始标记阶段的时间稍长,远远比并发标记阶段时间短(主要用到三色标记里的增量更新算法)
并发清理:开启用户线程,同时GC线程开始对未标记的区域做清扫,如果有新增对象会被标记为黑色不做处理
并发重置:重置本次GC过程中的标记数据。
缺点:1.对cpu资源敏感(会和服务器抢资源);2.无法处理浮动垃圾,只能等下一次gc的时候处理;3.使用标记清除算法,产生内存算法,可以用-XX:+UseCMSCompactAtFullCollection在标记清除之后在做整理;4.concurrent mode failure 上一次gc还没结束,就再次出发full gc,此时会STW用Serial Old来收集(并发失败,就别并发了)
CMS的相关核心参数:
-XX:+UseConoMarkSweepGC 启用cms
-XX:ConcGCThreads 并发的GC线程数
-XX:+UseCMSCompactAtFullCollection Full gc之后做压缩整理(减少碎片)
-XX:CMSFullGCBeforeCompaction 多少次GC之后压缩一次,默认0,表示每次Full gc之火都会压缩一次
-XX:+CMSInitiatingOccupancyFration 当老年代使用达到该比例时会触发Full gc(默认92 这是百分比)
-XX:+UseCMSInitiatingOccupancyOnly 只是用设定的回收阈值(-CMSInitiatingOccupancyFration设定的值),如果不指定,JVM在第一次使用设定值,后续则自动调整。
+XX:+CMSScavengBeforeRemark 在CMS gc前启动一次minor gc,目的在于减少老年代对年轻代的引用,降低CMS gc标记阶段时的开销,一般CMS的gc耗时80%在标记阶段
-XX:+CMSParallelInitialMarkEnabled 表示在初始标记的时候多线程执行,缩短STW
-XX:+CMSParalleRemarkEnabled 在重新标记的时候多线程执行缩短STW -
G1收集器(待补充)
-XX:+UseG1GC
取消物理分代,2048个Region,每个Region还是有分代概念:eden、s0、s1、old、humongous(大对象,对象大于Region的50%就会放在这里),角色会变。
根据参数制定回收计划(让STW不超过某个时间) -XX:MaxGCPauseMills,在这个时间内回收部分垃圾,这个时间不宜过短。
G1收集器 -
ZGC (待补充)
垃圾收集底层算法实现
三色标记
- 黑:表示对象已经被扫描过,且该对象的所有引用都已经扫面过,它时安全存活的,如果有其他的对象指向黑色对象无需重新扫描,黑色对象不能直接(不经过灰色对象)指向某个白色对象;
- 灰:该对象已经被访问过,但是这个对象上至少存在一个引用还没有被扫描过
- 白:尚未被垃圾垃圾收集器访问,可达性分析刚开始的时候都是白色的,如果分析结束时,仍然是白色的,即不可达。
并发标记过程中可能发生:
多标
浮动垃圾,下一次gc处理
漏标:(写屏障处理)
增量更新(写后屏障):新增引用记录起来,重新标记
原始快照SATB(写前屏障):根据原始快照直接标黑,真是垃圾就成浮动垃圾
记忆集与卡表
解决跨代引用
新生代维护一片区域存放老年代引用新生代对象的引用,记忆集Remember set,底层实现用卡表Cardtable(其实就是字节数组,写屏障实现)