返回介绍

上卷 程序设计

中卷 标准库

下卷 运行时

源码剖析

附录

3.6.1 写屏障

发布于 2024-10-12 19:16:04 字数 2040 浏览 0 评论 0 收藏 0

所有对象都属于白、灰和黑色中一种。在 GC 开始时,所有对象都是白色。

目标是将所有可达对象标记为黑色,并释放所有白色对象。

先从根对象(全局变量、堆栈等)开始扫描,将可达对象标记为灰色,添加到待处理队列。

接下来,从队列取出灰色对象,其自身标记为黑色。将被其引用的对象标记为灰色,放入队列。

如此,在处理完灰色队列后,仅剩黑白两色。

最终约束: 黑色对象不能引用白色。(黑色活着,那么它引用的必然也活着,也是黑色)

由于并发的缘故,某个已被标记为黑色的对象,可能被用户代码 “突然” 指向一个白色对象。

此时,要保证该约束,就需要写屏障(write barrier)机制介入。

当写屏障启用时,对黑色对象内部指针修改会引发写屏障调用,以便有机会标记所引用对象。

写屏障有助于减少重新扫描操作,简化和消除垃圾回收器的复杂机制。并在一定程度上缩减了 STW 时间。

写屏障由编译器插入相应指令实现。

在 gcStart setGCPhase(_GCmark) 时, writeBarrier.enabled = true

// mgc.go

func setGCPhase(x uint32) {
    atomic.Store(&gcphase, x)
    
    writeBarrier.needed = gcphase == _GCmark || gcphase == _GCmarktermination
    writeBarrier.enabled = writeBarrier.needed || writeBarrier.cgo
}

example

下面的例子,试图修改根指针对象 x。反汇编可以看到,编译器在尾部插入了写屏障函数调用。

在正常赋值之前,先检查 writeBarrier.enabled 字段,看写屏障是否启用(GC Mark, setGCPhase)。

如此看,除进入并发标记阶段外,正常情况下的性能影响很小。

// mgc.go

var writeBarrier struct {
    enabled bool         // compiler emits a check of this before calling write barrier
    ...
}
package main

var x *int

func main() {
	x = new(int)
	println(x)
}
$ go build -gcflags "-S"

"".main STEXT size=138 args=0x0 locals=0x18
	 00029     LEAQ	type.int(SB), AX
	 00036     MOVQ	AX, (SP)
	 00040     CALL	runtime.newobject(SB)         // 将 new(int) 返回值保存到 AX
	 00045     MOVQ	8(SP), AX

	 00050     CMPL	runtime.writeBarrier(SB), $0  // 判断 writeBarrier.enabled
	 00057     JNE	111                           // 按标志位结果跳转
	 00059     MOVQ	AX, "".x(SB)                  // 否则保存到 main.x

	 00066     CALL	runtime.printlock(SB)
	 00071     MOVQ	"".x(SB), AX
	 00078     MOVQ	AX, (SP)
	 00082     CALL	runtime.printpointer(SB)
	 00087     CALL	runtime.printnl(SB)
	 00096     CALL	runtime.printunlock(SB)

	 00110     RET

	 00111     LEAQ	"".x(SB), DI
	 00118     CALL	runtime.gcWriteBarrier(SB)
	 00123     JMP	66

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文