go1.13之Error Warp
本文给出使用go1.13 defer时应该避免的姿势。
性能提升30%的原理和defer本身的原理不做介绍。这两项可分别参考资料1,2,3。
资料1简单给出性能提升的一些关键点。重点是原来defer语法依赖的_defer数据结构只能分配在堆上,新版本中可以针对性分配在栈上。免去了systemstack()或mallocgc()带来的开销。
资料2-3详细介绍了defer原理;此原理在go1.13版本中不过时,因为go1.13的优化场景具有针对性。
简单来说,要想享受defer带来的30%性能提升。以下两种场景的代码要避免:
defer语句外层嵌套有显式循环; defer语句有隐式循环; 显式循环考虑以下代码
1 2 3 4 5 6 7 package main func main() { for i := 0; i <= 0; i++ { defer func() {}() } } 看汇编结果,底层调用的是runtime.deferproc。还是老方式,即_defer对象分配在堆上。
1 2 3 4 "".main STEXT size=121 args=0x0 locals=0x20 # ... 0x0047 00071 (main.go:5) CALL runtime.deferproc(SB) # ... 注意循环只执行一次,实际只要它有循环次数,都是在堆上分配对象。等于性能优化享受不了。
1 2 for i := 0; i <= -1; i++ {} // 堆和栈都不分配。因为循环不被执行 for i := 0; i <= [等于或大于0的任何正整数]; i++ {} // 分配在堆上 隐式循环考虑以下代码
GODEBUG之gctrace解析
golang标准库sync.Pool原理及源码简析
pool关键作用:
- 减轻GC的压力。
- 复用对象内存。有时不一定希望复用内存,单纯是想减轻GC压力也可主动给pool塞对象。