go 内存逃逸分析
目录
一、什么是逃逸分析
二、为什么需要逃逸分析?
三、逃逸发生的常见场景
1. 返回局部变量的指针
2. 将变量赋值给包级全局变量或外部引用的指针
3. 将变量传递给 interface{} 参数(可能逃逸,取决于函数内是否存储引用)-不必要
改正方法
4. 闭包捕获变量
5. 切片或 map 存储指针(或本身需要扩容)-不必要
改正方法
6. 发送到 channel 的指针
三、如何查看逃逸分析结果?
四、逃逸分析与栈分配的关系图
五、性能影响与优化建议
性能差异
优化建议
六、典型反例:循环中取地址
七、常见的坑
八、总结
一、什么是逃逸分析
逃逸分析 是 Go 编译器在编译阶段执行的一项静态分析技术,用于判断一个变量的内存是分配在栈上还是堆上。
它的核心结论是:如果变量在函数返回后仍然可能被引用,则它会“逃逸”到堆上;否则,它优先分配在栈上。
二、为什么需要逃逸分析?
| 分配位置 | 优点 | 缺点 |
|---|---|---|
| 栈上分配 | 分配/释放极快(仅移动栈指针),无需 GC 扫描 | 函数返回后自动销毁,无法跨函数保持 |
| 堆上分配 | 可跨函数访问,生命周期灵活 | 分配较慢,需要 GC 管理,增加 GC 压力 |
逃逸分析的目标:尽量把变量分配在栈上,减少堆分配,从而降低 GC 负担、提升性能。
三、逃逸发生的常见场景
1.返回局部变量的指针
func newInt() *int { x := 42 return &x // x 逃逸到堆上,因为返回后仍需访问 }2.将变量赋值给包级全局变量或外部引用的指针
var global *int func setGlobal() { x := 42 global = &x // x 逃逸到堆上 }3.将变量传递给 interface{} 参数(可能逃逸,取决于函数内是否存储引用)-不必要
func printInterface(v interface{}) { fmt.Println(v) } func main() { x := 42 printInterface(x) // x 可能逃逸,因为 interface{} 可能持有引用 }为什么会逃逸?
interface{}是一个包含类型和指
