前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >go: GC时写屏障与栈的引用变化

go: GC时写屏障与栈的引用变化

作者头像
超级大猪
发布2021-01-06 15:25:07
2.1K0
发布2021-01-06 15:25:07
举报
文章被收录于专栏:大猪的笔记大猪的笔记

参考

https://studygolang.com/articles/30067

前言

关于三色收集和屏障技术的文章已经很多。先总结一下背景知识: 1. go使用混合屏障。删除屏障:假设A--ref-->B,ref断开时会对B染色。插入屏障:假设GC时,有新的引用C--ref2-->E,E也会被染色。 2. 上面的屏障保护只发生在堆的对象上。因为性能考虑,栈上的引用改变不会引起屏障触发。

先举个最常见例子:

  1. 初时,栈A对象引用了C对象。栈B引用了D对象。
  2. 在GC时,栈1和A对象已被扫黑。
  3. 此时解除B-->D的引用,同时,新建引用C-->D。
  4. 因为有插入屏障,D会被染色,不会被误回收。

附上代码:

代码语言:javascript
复制
writePointer(slot, ptr):
    shade(*slot) // 删除屏障
    if current stack is grey: // 这行可以忽略
        shade(ptr) // 插入屏障
    *slot = ptr

大部分文章,都在这戛然而止。留下无限的遐思。

然而,我们是思考者:

  1. 为什么写屏障不保护栈的引用,为什么栈上触发写屏障就会影响性能?
  2. 如果发生栈上对象引用改变。因为不涉及屏障,为什么不会发生错误。

问题1很好解答,因为go是并发运行的,大部分的操作都发生在栈上。数十万goroutine的栈都进行屏障保护自然会有性能问题。

关键是,如果屏障不保护栈的引用,那如何保证正确性。

设想下面的场景:

  1. 故事发生在两个goroutine上
  2. 栈1已被扫黑,它下面的对象都是灰色
  3. 栈2还未被扫黑,所以它引用的D可能是白色。
  4. 在GC之时,解除ref2,并且将ref指向D。
  5. 因为引用改变都发生在栈上,不会触发屏障。所以D被回收?

因为这是一个伪命题:

  1. 对栈的操作是原子操作,要么栈全灰,要么全黑。
  2. 已被扫黑的栈,引用的堆上的对象至少是灰色。(比如C对象)。所以不可能发生同栈下引用改变会影响GC的问题。
  3. 不可能发生上述的跨栈的引用。因为“对象不是从天上掉下来的”。假设A对象可以与D对象建立引用,只有可能A也直接间接持有B对象。否则没有路径可以建立这样的引用。然而,因为Go的逃逸分析,B对象被外部引用,不可能存在于栈上。所以B一定是堆上的对象。
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2021-01-05 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 参考
  • 前言
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档