上卷 程序设计
中卷 标准库
- bufio 1.18
- bytes 1.18
- io 1.18
- container 1.18
- encoding 1.18
- crypto 1.18
- hash 1.18
- index 1.18
- sort 1.18
- context 1.18
- database 1.18
- connection
- query
- queryrow
- exec
- prepare
- transaction
- scan & null
- context
- tcp
- udp
- http
- server
- handler
- client
- h2、tls
- url
- rpc
- exec
- signal
- embed 1.18
- plugin 1.18
- reflect 1.18
- runtime 1.18
- KeepAlived
- ReadMemStats
- SetFinalizer
- Stack
- sync 1.18
- atomic
- mutex
- rwmutex
- waitgroup
- cond
- once
- map
- pool
- copycheck
- nocopy
- unsafe 1.18
- fmt 1.18
- log 1.18
- math 1.18
- time 1.18
- timer
下卷 运行时
源码剖析
附录
文章来源于网络收集而来,版权归原创者所有,如有侵权请及时联系!
3.6.1 写屏障
所有对象都属于白、灰和黑色中一种。在 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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论