JVM G1 源码分析02 新生代回收 && 混合回收 && full gc

YGC的流程如下:

首先STW,YGC全过程都在STW时进行,不需要考虑并发场景
选择CSet(Collection Set),YGC中CSet即为全部新生代Region
根扫描
更新RSet
深度复制更新对象到Survivor Region
重构RSet
释放CSet
大对象回收
动态扩展内存
动态调整新生代Region数量
启动并发标记,判断是否需要紧接着进行一次混合式GC
 

GC并行任务包括跟扫描、更新RSet、对象复制,主要逻辑在g1CollectedHeap.cpp G1ParTask类的work方法中;evacuate_roots为根扫描。

  • 处理java根
  • 处理jvm根
  • 处理string table根
  • 处理所有已加载类的元数据
  • 处理所有Java线程当前栈帧的引用和虚拟机内部线程
  • 处理JVM内部使用的引用(Universe和SystemDictionary)
  • 处理JNI句柄
  • 处理对象锁的引用
  • 处理java.lang.management管理和监控相关类的引用
  • 处理JVMTI(JVM Tool Interface)的引用
  • 处理AOT静态编译的引用

处理StringTable JVM字符串哈希表的引用

JVM G1 源码分析02 新生代回收 && 混合回收 && full gc

根据age判断copy到新生代还是老年代
先尝试在PLAB中分配对象
PLAB分配失败后的逻辑与TLAB类似,先申请一个新的PLAB,在旧PLAB中填充dummy对象,在新PLAB中分配,如果还是失败,则在新生代Region中直接分配
如果还是失败,则尝试在老年代Region中重新分配
age加1,由于锁升级机制,当对象锁状态是轻量级锁或重量级锁时,对象头被修改为指向栈锁记录的指针或者互斥量的指针,修改age需要特殊处理
对于字符串去重的处理
如果是数组,且数组长度超过ParGCArrayScanChunk(默认50)时,将对象放入队列而不是深度搜索栈中,防止搜索时溢出
 

2.2.3 深度搜索复制

G1ParTask的work函数调用evac.do_void()进行对象复制

并行线程处理完当前任务后,可以窃取其他线程没有处理完的对象

调用do_oop_evac复制一般对象,调用do_oop_partial_array处理大数组对象
如果对象已经复制,则无需再次复制
否则,调用copy_to_survivor_space复制对象
更新引用者field地址
如果引用者与当前对象不在同一个分区,且引用者不在新生代分区中,则更新RSet信息入队