JVM G1源码分析和调优书 阅读笔记 第7章 Full GC
对象分配失败,就会进入到Evac失败过程,在GC日志详情中会打印相关信息
1.处理失败
2.再次尝试分配,仍然不成功,进行Full GC
7.1 Evac失败
把对象放入到Evac失败栈;直接更新对象的RSet,不需要对已复制的对象做额外回收之类的处理
检查是否有指向自己的指针,如果有,就代表发生了复制失败。需要删除指针,恢复对象头
1. 把这个分配失败的对象,放入到特殊的dirty card队列中
2.执行Redirty重构整个RSet,确保引用的正确性
7.2 FGC
JDK10之前,FGC都是串行回收;需要停止并发标记,停止增量回收
串行回收采用标记清除算法
7.2.2 计算对象的新地址
7.2.3 更新引用对象的地址
遍历活跃对象,然后把活跃对象和活跃对象中的引用更新到新位置
7.2.4 移动对象完成压缩
遍历必须从前向后依次开始,否则数据会被破坏
把对象复制到新的地址,然后重新设置对象头,这就是压缩工作
7.2.5 后处理
分区并没有发生调整,仅仅把已经死亡的对象回收,活跃的对象仍然保留在本分区内
1.尝试调整整个堆空间的大小,利用期望值和实际值的比较来判断是否需要扩展或者收缩堆空间
2.遍历堆,重构RSet,否则下一次GC就会丢失根集合,导致回收错误。重构RSet,对每一个分区根据对象的引用关系重构RSet
3.清除dirty card队列,并把所有的分区都认为是old分区
4.最后记录各种信息,同时调整YGC的大小
7.3 并行FGC
7.3.1 并行标记
类似于并发标记,但是不涉及SATB处理
并行标记任务主要在G1FullGCMarkTask完成,多个GC从不同的根出发,完成标记,当线程任务完成后,可以尝试窃取别的线程尚未处理完的对象进行标记
7.3.2 计算对象的新地址
计算新地址可以把这一批分区里面的对象,进行压缩,这样就可能出现完全空闲的分区。
7.3.3 更新引用对象的地址
从根集合出发遍历活跃对象,然后把活跃对象和活跃对象中的引用都更新到新的位置
7.3.4 移动对象完成压缩
7.3.5 后处理
恢复对象头,更新各种信息