G1垃圾收集器
堆的逻辑划分
堆被划分了多个同等份的区域,每个区域叫做Region
Humongous(大对象)区域
- 存储特别大的对象(大于Region内存的一半)
- 若没有引用指向大对象,就可直接在Minor GC中被回收掉
对于「小区域」回收容易控制它的「收集时间」(STW)
Minor GC(Young GC)
触发时机同之前,等到Eden区满了之后会触发
年轻代和老年代占堆空间(有参数设置)
- 会动态根据「最大停顿时间」进行调整,控制MInor GC开销
GC过程
-
根扫描
- 同初始化标记
-
更新、处理 RSet
-
Rset:同CMS中卡表,在G1中Rset解决「跨代引用」
- 每个Region都有,记录着「其他Region引用了当前Region的对象关系」
- 对于年轻代Region:RSet 只保存来自老年代的引用
- 对于老年代的 Region ,RSet 也只会保存老年代对它的引用 (G1老年代回收之前,都会先对年轻代进行回收,所以没必要保存年轻代的引用)
-
将老年代对象持有年轻代对象的相关引用都加入到GC Roots下,避免被回收掉
-
-
复制对象
- 扫描存活的对象往「空的Survivor区」或「老年代」存放,其他的Eden区进行清除
-
Cset
-
保存了一次GC中「将执行垃圾回收」的Region。CSet中的所有存活对象都会被转移到别的可用Region上
- 在Minor GC 的最后,会处理软引用、弱引用、JNI Weak等引用,结束收集
-
Mixed GC
触发机制
-
当堆空间的占用率达到一定阈值后会触发。默认45%
-
依赖「全局并发标记」统计后的Region数据(类似CMS)
- 一定会回收年轻代,并会部分回收老年代 “混合”GC
GC过程
-
初始标记(STW)
- 扫描GC Roots 一层
-
并发标记
- 从GC Roots往下追溯,GC线程负责收集各个 Region 的存活对象信息
-
重新标记(STW)
-
标记那些在「并发标记」阶段发生变化的对象
-
使用SATB算法解决「并发标记」阶段导致引用变更的问题(漏标)
-
灰色-白色引用消失时
- 引用会被push到堆栈,下次扫描时拿到这个引用,由于Rser存在,不需要扫描整个堆去查找指向白色的引用,效率高
-
GC 开始的时候,为存活对象做一次「快照」
-
在「并发阶段」时,把每一次发生引用关系变化时旧的引用值给记下来
- 在「重新标记」阶段只扫描着块「发生过变化」的引用,看有没有对象还是存活的,加入到「GC Roots」上
-
-
STAB存在的问题:在开始时G1就认为它是活的,那就在此次GC中不会对它回收,即便可能在「并发阶段」上对象已经变为了垃圾。
-
-
-
清理(STW)
- 根据「停顿预测模型」(设定的停顿时间)决定本次GC回收多少Region。主要清点和重置标记状态
- Mixed GC 进行清除是通过「拷贝」的方式
Full GC
如果在Mixed GC中无法跟上用户线程分配内存的速度,导致老年代填满无法继续进行Mixed GC,就又会降级到serial old GC来收集整个GC heap
三色标记
-
产生C浮动垃圾
- 漏标:黑色指向白色若不重新扫描黑色,会把C当作没有新引用而回收