简单介绍 g1gc Snapshot-At-The-Beginning与Remembered Sets

Snapshot-At-The-Beginning

  • 标记方式有两种方式

    • 增量更新(Increment Update)
    • 初始快照( Snapshot At The Beginning SATB)
  • SATB( Snapshot At The Beginning, 初始快照) 是一种将并发标记阶段开始时对象间的引用关系, 以逻辑快照的形式进行保存的手段

  • 介绍并发标记

    • 介绍简单标记

      • 在简单标记中, 所有可从根直接触达的对象都会被添加标记。 带标记的是存活对象, 不带标记的是死亡对象 在这里插入图片描述
    • 标记位图

      • 将用于标记的比特值等信息单独拿出来放到其他地方, 用来匹配对应的对象。

      • 在这里插入图片描述

        • bottom 表示区域内众多对象的末尾
        • nextTAMS 中的 TAMS 是“Top At Marking Start”(标记开始时的 top) 的缩写
        • nextTAMS 保存了本次标记开始时的 top, 而 prevTAMS 保存了上次标记开始时的 top。
        • next 是本次标记的标 记位图
        • prev 是上次标记的标记位图, 保存了上次标记的结果
  • 流程

    1. 初始标记阶段

      1. GC 线程首先会创建标记位图 next
      2. nextTAMS 指的 就是标记开始时 top 所在的位置, 所以在这里我们将它和 top 对齐
    2. 并发标记阶段

      1. 概念:在并发标记阶段, GC 线程继续扫描在初始标记阶段被标记过的对象, 完成对大部分存活对象的标记

      2. 这个阶段是与用户线程并发执行的,那怎么来标记呢

      3. 首先根据快照,来标记各个引用。

      4. new 新对象

      5. 对象成员变量的变化

        1. 记录引用关系,所以需要写屏障技术,称之为 SATB 专用写屏障。

        2. 伪代码

        3.     1: def satb_write_barrier(field, newobj):
              2:   if $gc_phase == GC_CONCURRENT_MARK:
              3:      oldobj = *field // (a)
              4:      if  oldobj != Null:
              5:          enqueue($current_thread.stab_local_queue, oldobj) // (b)
              6:
              7:      *field = newobj // (c)
          
        4. 加入队列后的处理

          1. 只扫描未被标记的
          2. 已经标记的不处理
        5. 并发标记阶段结束后区域的状态

        6. 疑问

          1. 多线程环境下如何加入队列
            1. 由GC线程来处理
            2. 绑定线程队列
            3. 线程本地队列满了,再放入全局队列
          2. 并发写一个字段,如果obj3对象field引用了objo, 两个线程并发赋值obj1,obj2. 导致obj1没有加入队列,那obj1会丢失吗
            1. obj1有两种可能,一种是new的,一种是另一个引用。

            2. obj1 未被 SATB 专用写屏障获知时对象之间的关系

            3. 那obj4移除对obj1的引用会有问题吗

      6. 最终标记阶段

        1. 未装满的 SATB 本地队列
      7. 存活对象计数

        1. 这个步骤会扫描各个区域的标记位图 next, 统计区域内存活对象的字节数
      8. 收尾工作

        1. next_marked_bytes 替换为prev_marked_bytes,同时, prevTAMS 被移到了 nextTAMS 先前的位置
    • 总的流程图

remembered set

  1. SATB 队列集合主要用 来记录标记过程中对象之间引用关系的变化
  2. 转移专用记忆集合则用
    来记录区域之间的引用关系。 通过使用转移专用记忆集合, 在转移时即
    使不扫描所有区域内的对象, 也可以查到待转移对象所在区域内的对象
    被其他区域引用的情况, 从而简化单个区域的转移处理
  3. 那为什么要使用remembered set,什么情况下使用
    1. 减少全扫描

    2. 分代垃圾回收,之间是怎么引用的

      1. 分区内部引用
        1. 无论是新生代还是老年代的分区内部的引用,都不需要记录引用关系。因为是针对一个分区进行的垃圾回收,要么这个分区被回收,要么不被回收。
      2. 年轻代与年轻代之间的引用
        1. G1 的三种回收算法(YGC/MIXED GC/FULL GC)都会全量处理新生代分区,所以新生代都会被遍历到。因此无需记录这种引用关系。
      3. 年轻代引用年老代
        1. 无需记录。G1 的 YGC 回收新生代,无需这个引用关系。混合 GC 时,G1 会采用新生代分区作为根,那么在遍历新生代分区时就能找到老年代分区了,无需这个引用关系。对于 FGC 来说,所有分区都会被处理,也无需这个引用关系。
      4. 年老代引用年轻代
        1. 需要记录。YGC 在回收新生代时,如果新生代的对象被老年代引用,那么需要标记为存活对象。即此时的根对象有两种,一个是栈空间 / 全局变量的引用,一个是老年代到新生代的引用。
      5. 年老代引用年老代
        1. 需要记录。混合 GC 时,只会回收部分老年代,被回收的老年代需要正确的标记哪些对象存活。
    3. 记录引用方式

      1. point -in
      2. point-out
    4. 如何记录引用关系

      1. 对象与对象的引用
      2. region 与 region
      3. 对象与region
      4. region 与 卡表(Card Table)
    5. Card Table

    6. 卡表是由元素大小为 1 B 的数组实现的(图 3.3) 。 卡表里的元素称为卡片

      1. 在这里插入图片描述

      2. 卡表的实体是数组。 数组的元素是 1 B 的卡片, 对应了堆中的 512 B。 脏卡片用灰色表示, 净卡
        片用白色表示

      3. 根据对象获取对应的卡表

        1. 卡表的实体是数组。 数组的元素是 1 B 的卡片, 对应了堆中的 512 B。
        2. (对象的地址 - 堆的头部地址)/ 512
      4. 因为卡片的大小是 1 B, 所以可以用来表示很多状态。 卡片的种类很多, 我们主要关注以下两种

        1. 净卡片
        2. 净卡片
    7. 记忆集合的构造

      1. 每个区域中都有一个转移专用记忆集合, 它是通过散列表实现的。 散列
        表的键是引用本区域的其他区域的地址, 而散列表的值是一个数组, 数
        组的元素是引用方的对象所对应的卡片索引。
    8. 写屏障

      1. 当对象的域被修改时, 被修改对象所对应的卡片会被转移专用写屏障记
        录到转移专用记忆集合中。 转移专用写屏障的伪代码如代码清单

      2. 多线程优化

    9. 记忆集合维护线程

      1. 转移专用记忆集合维护线程主要进行下列处理
        1. 从转移专用记忆集合日志的集合中取出转移专用记忆集合日志, 从
          头开始扫描
        2. 将卡片变为净卡片
        3. 检查卡片所对应存储空间内所有对象的域
        4. 往域中地址所指向的区域的记忆集合中添加卡片
    10. 热卡片

      1. 频繁发生修改的存储空间所对应的卡片称为热卡片(hot card)
      2. 热卡
        片可能会多次被转移专用记忆集合维护线程处理成脏卡片, 从而加重转
        移专用记忆集合维护线程的负担, 因此需要特别处理。
      3. 卡片计数表,它记录了卡片变成脏卡片的次
        数。
      4. 脏卡片阈值(默认是 4)
    11. 那GC时,记忆集合如何转移呢

转移对象

  1. 是指参考并发标记提供的信息来选择被转移的区域。 被选中的区域称
    为回收集合
  2. 是指将回收集合内由根直接引用的对象, 以及被其他区域引用的对象
    转移到空闲区域中。
  3. 是指以②中转移的对象为起点扫描其子孙对象, 将所有存活对象一并
    转移。 当③结束之后, 回收集合内的所有存活对象就转移完成了。
  4. 伪代码 在这里插入图片描述
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值