Go Runtime: WriteBarrier

2023-11-02 10:23:49 +08:00
 GopherDaily

在阅读 Go runtime 相关的代码时, 我们可以看到大量 write barrier 相关的代码或者注释, 大概可以猜到是和 GC 相关的, 具体用途和原理之前确并不知晓.

Go 的垃圾回收可以被简化为两个步骤: 标记(mark)和清除(sweep).

GC 在标记阶段并不暂停所有协程的执行. 这就需要我们考虑, 如果对象的引用关系在标记阶段被修改了应该怎么办?

假设:

由于 C 仅被 A 引用, 但 A 已被标记为黑色, 所以 GC 不会再去标记 C. 在随后的清除阶段, 虽然 C 依然被引用, 但是会因为未被标记而被 GC 的回收, 这显然时不可接受的.

为了处理这种情况, Go 引入 write barrier, 即由编译器在需要的地方插入相关代码处理.

我们构造一个相关的例子:

var sink *int

func main() {
        foo := []int{1, 2, 3}
        sink = &foo[1]
}

在生成的汇编代码中我们可以找到相关内容:

cat -n objdump | grep -A 100 "main.main>:"
...
138038          sink = &foo[1]
138039    4576b1:       48 8d 48 08             lea    0x8(%rax),%rcx
138040    4576b5:       83 3d d4 10 0a 00 00    cmpl   $0x0,0xa10d4(%rip)        # 4f8790 <runtime.writeBarrier>
138041    4576bc:       74 15                   je     4576d3 <main.main+0x53>
138042    4576be:       66 90                   xchg   %ax,%ax
138043    4576c0:       e8 1b d2 ff ff          call   4548e0 <runtime.gcWriteBarrier2>
138044    4576c5:       49 89 0b                mov    %rcx,(%r11)
138045    4576c8:       48 8b 05 51 32 07 00    mov    0x73251(%rip),%rax        # 4ca920 <main.sink>
138046    4576cf:       49 89 43 08             mov    %rax,0x8(%r11)
138047    4576d3:       48 89 0d 46 32 07 00    mov    %rcx,0x73246(%rip)        # 4ca920 <main.sink>
...

其逻辑是:

Link: https://github.com/j2gg0s/j2gg0s/blob/main/_posts/2023-11-01-Go%20Runtime%3A%20WriteBarrier.md

863 次点击
所在节点    Go 编程语言
0 条回复

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/987748

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX