一般来说,局部变量会在函数返回后被销毁,因此被返回的引用就成为了 “无所指” 的引用,程序会进入未知状态。但这在 Go 中是安全的,Go 编译器将会对每个局部变量进行逃逸分析。如果发现局部变量的作用域超出该函数,则不会将内存分配在栈上,而是分配在堆上,因为他们不在栈区,即使释放函数,其内容也不会受影响。例如:
func add(x, y int) *int {
res := 0
res = x + y
return &res
}
func main() {
fmt.Println(add(1, 2))
}
上面函数局部变量 res
发生了逃逸,其作为返回值将在 main
中继续使用,所以其指向的内存不能分配到栈上(函数结束调用将会被回收),所以只能分配在堆上。
提示
编译时可以借助选项 -gcflags=-m
,查看变量逃逸的情况
提示
程序中的数据和变量都会被分配到程序所在的虚拟内存中,内存空间包含两个重要区域:栈区(Stack)和堆区(Heap)。函数调用的参数、返回值以及局部变量大都会被分配到栈上,这部分内存会由编译器进行管理;而堆中的对象由内存分配器分配并由垃圾收集器回收。