NOTICE:本文仅记录本人对 JVM G1 的小小理解,没有详细记录每个点,若有误可指出
内存区域
G1 将堆分为各个 region,大小通过 G1HeapRegionSize 指定
region 分类
按 region 大小分
- 普通 region,存放大小小于普通 refion 容量的一半的对象
- humongous 区域,存放大对象
按功能来分
- 新老代
- 老年代(humongous 只能在老年代)
新对象进入
- 新对象根据大小进入普通 region /humongous
- 记忆集维护
- 本 region 维护一个记忆集,记忆集都是别的 region 对象指向本 region 的引用
- 写前屏障,处理 SATB,将修改前引用对象放入 SATB 队列
- 写后屏障,标记被修改的对象所在卡表为 dirty card
垃圾回收
回收依据
维护每个 region 中垃圾的价值(回收获得的空间大小以及所需时间的比值)大小,通过最大 GC 时间(-XX:MaxGCPauseMillis)优先处理价值大的 region
回收分类
- Young GC
- Mixed GC(老年代中的内存比例超过IHOP)
回收步骤
- 初始标记
- 标记 GC Root 直接关联的对象
- 生成原始快照
- 修改 TAMS 的值
- 需要 Stop the world
- 并发标记
- 从 GC Root 开始进行可达性分析
- 处理 SATB 记录的引用变动的对象
- 最终标记
- 处于并发阶段遗留的少量 SATB 记录
- 筛选回收
- 计算各个 region 回收价值
- 回收
- 将回收 region 中存活对象挪到空 region 中
- 清空原有 region
标记过程中问题处理
- 在并发标记中,有新对象生成
- 通过 TAMS 划分特定区域
- 新对象只能放在 TAMS 区域中,并且默认是黑色的
- 在并发标记进行可达性分析,引用变动的对象处理
- 使用 SATB 记录灰色到白色删除的引用
- 在最终标记以灰色的对象为根,重新扫描一次
停顿分析
- 初始标记是 STW 的,但是只标记 GC Root,所以停顿时间较短
- 并发标记因为是与应用线程并发进行的,所以即使需要进行可达性分析,但是也不会停顿
- 最终标记,因为并发标记漏的对象比较少,所以即使 STW,停顿也不长
- 筛选回收,因为 G1 实际是用的是复制算法,复制对象时间可能较长,所以耗时较多是在此阶段
概念解释
三色标记法
- 黑色意义为被访问过的对象,引用都扫描过,并且确认最后是存活的,GC Root 默认为黑色
- 灰色意义为被访问过的对象,有一个引用未被扫描过,未确定是否存活
- 白色意义为未被访问过的对象
对并发标记中对象引用变化处理
SATB
- 全称为 Snapshot At The Beginning
- Region 包含 5 个指针
- bottom
- previous TAMS
- next TAMS
- top
- end
- 作用流程
- 并发标记中,新创建的对象在 next TAMS -> top 之间,此区间默认为黑色,默认存活
- 灰色对象删除指向白色的引用,记录下来
- 以记录下来的灰色为根,重新扫描
Incremental Update
- 黑色插入新的指向白色的引用,记录下来
- 并发扫描结束后,以记录下来的黑色为根,重新扫描一遍
参考
https://blog.51cto.com/u_15072811/4679940
本文首发于cartoon的博客
转载请注明出处:https://cartoonyu.github.io