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