golang 垃圾回收(四)删除写屏障 2020/5/27 13:00

奇伢云存储 · · 952 次点击 · · 开始浏览    
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

  • 接上一篇 golang 垃圾回收的梳理,这篇讲删除写屏障,golang 的内存写屏障是由插入写屏障到混合写屏障过渡的。虽然 golang 从来没有直接使用删除写屏障,但是混合写屏障却用到了删除写屏障的思路。

    删除写屏障:也叫做基于其实快照的解决方案(snapshot-at-the-begining)。故名思义,就是在开始 gc 之前,必须 STW ,对整个根做一次起始快照。当赋值器(业务线程)从灰色或者白色对象中删除白色脂针时候,写屏障会捕捉这一行为,将这一行为通知给回收器。
    这样,基于起始快照的解决方案保守地将其目标对象当作存活的对象,这样就绝对不会有被误回收的对象,并且还有工作量浮动放大的风险。术语叫做追踪波面的回退。

    删除写屏障(基于起始快照的写屏障)有一个前提条件,就是起始的时候,把整个根部扫描一遍,让所有的可达对象全都在灰色保护下(根黑,下一级在堆上的全灰),之后利用删除写屏障捕捉内存写操作,确保弱三色不变式不被破坏,就可以保证垃圾回收的正确性。

    伪代码如下:

    atomic Write(src, i, ref)
        shade(src[i])
        src[i] <- ref
    
    

    复习一下一些概念

    赋值器的颜色

    • 灰色赋值器:如果某一哥赋值器尚未被回收器扫描过(即赋值器的根还没有被追踪到),或者尽管被扫描过,但是还需要重新扫描
      • golang 插入写屏障的时期,就是灰色赋值器
    • 黑色赋值器:已经被回收器扫描过,不会再对其进行扫描

    插入写屏障对应的是灰色赋值器,删除写屏障对应的是黑色赋值器。

    三色不变式

    • 强三色:不允许黑色对象指向白色对象
    • 弱三色:允许黑色对象指向白色对象,但必须保证一个前提,这个白色对象必须处于灰色对象的保护下

    强三色不变式要求黑色赋值器的根只能引用灰色或者黑色对象,不能引用白色对象(因为黑色赋值器不再被扫描,引用白色)。弱三色不变式允许黑色赋值器的根引用白色对象,但前提是白色对象必须处于灰色保护下。

    获取赋值器的快照,意味着回收器需要扫描其根并将其着为黑色。我们必须在回收起始阶段完成赋值器快照的获取,并保证其不持有任何白色对象。否则一旦赋值器持有某白色对象的唯一引用并将其写入黑色对象,然后再抛弃该脂针,则会违背弱三色不变式的要求。为黑色对象增加写屏障可以捕捉这一内存写操作,但如此依赖,该方案将退化到强三色不变式的框架下。因此,基于其实快照的解决方案将只允许黑色赋值器的存在。

    删除写屏障怎么保证弱三色不变式,如下示意图:

    image.png

    我们看到第三张图显示,黑色指向白色没问题,只要最后 delete 指针的时候 Z 对象置灰色,那么回收的正确性就可以保证。

    总结关键点

    1. 黑色可以指向白色,但是必须保证一个前提,该白色对象处于灰色保护链下
    2. 起始赋值器必须打快照,赋值器(根)扫描完成变成黑色,确保前提条件:所有对象都在灰色保护链下
    3. 插入写屏障对应的是灰色赋值器,删除写屏障对应的是黑色赋值器

坚持思考,方向比努力更重要。微信公众号关注我:奇伢云存储

扫码_搜索联合传播样式-白色版.png

有疑问加站长微信联系(非本文作者)

本文来自:简书

感谢作者:奇伢云存储

查看原文:golang 垃圾回收(四)删除写屏障 2020/5/27 13:00

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

952 次点击  
加入收藏 微博
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传