File tree Expand file tree Collapse file tree 1 file changed +34
-1
lines changed Expand file tree Collapse file tree 1 file changed +34
-1
lines changed Original file line number Diff line number Diff line change 11# 1.14 defer
22
3+ ## 正常处理流程
4+
35在 Go 1.14 中,增加了一种新的 defer 实现:open coded defer。当函数内 defer 不超过 8 个时,则会使用这种实现。
46
57``` go
@@ -264,7 +266,7 @@ DEFER 逻辑执行部分
264266 0x043a 01082 (open-coded-defer.go:31) LEAQ fmt.Println·f(SB), CX
265267 0x0441 01089 (open-coded-defer.go:8) JMP 188
266268
267- 这段代码没什么用,因为不会跳过来的,可能是可以优化的一个点
269+ 这段代码没什么用,只有在 panic 时,才可能跳到这里,但本例中无 panic
268270 0x0446 01094 (open-coded-defer.go:8) CALL runtime.deferreturn(SB)
269271 0x044b 01099 (open-coded-defer.go:8) MOVQ 344(SP), BP
270272 0x0453 01107 (open-coded-defer.go:8) ADDQ $352, SP
@@ -275,3 +277,34 @@ DEFER 逻辑执行部分
275277 0x045b 01115 (open-coded-defer.go:7) CALL runtime.morestack_noctxt(SB)
276278 0x0460 01120 (open-coded-defer.go:7) JMP 0
277279```
280+
281+ 超过 8 个 defer 时会退化回以前的 defer 链,也可以观察一下:
282+
283+ ``` go
284+ package main
285+
286+ func main () {
287+ defer println (1 )
288+ defer println (1 )
289+ defer println (1 )
290+ defer println (1 )
291+ defer println (1 )
292+ defer println (1 )
293+ defer println (1 )
294+ defer println (1 )
295+ defer println (1 )
296+ defer println (1 )
297+ }
298+ ```
299+
300+ 编译出的汇编就不贴了,和以前的没什么区别。
301+
302+ 可以做个简单的总结了:
303+
304+ * open coded defer 在函数内部总 defer 数量少于 8 时才会使用,大于 8 时会退化回老的 defer 链,这个权衡是考虑到程序文件的体积(个人觉得应该也有栈膨胀的考虑在)
305+ * 使用 open coded defer 时,在进入函数内的每个 block 时,都会设置这个 block 相应的 bit(ORL 指令),在执行到相应的 defer 语句时,把 defer 语句的参数和调用函数地址推到栈的相应位置
306+ * 在栈上需要为这些 defer 调用的参数、函数地址,以及这个用来记录 defer bits 的 byte 预留空间,所以毫无疑问,函数的 framesize 会变大
307+
308+ 参考资料:
309+
310+ 1 . [ open coded defer] ( https://github.com/golang/proposal/blob/master/design/34481-opencoded-defers.md )
You can’t perform that action at this time.
0 commit comments