前提
- 
栈区(stack):
- 由编译器自动分配释放 ,存放函数的参数值,局部变量的值等。
 - 操作方式类似于数据结构中的栈。
 - 内存分配比堆上快很多。
 
 - 
堆区(heap):
- 一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收 。
 - 它与数据结构中的堆是两回事。
 - 适合不可预知大小的内存分配。
 - 会引起Go频繁地进行垃圾回收,而垃圾回收会占用比较大的系统开销。
 - 会形成内存碎片。
 
 - 
我们通过 New() 函数获得的内存并非一定在堆上分配,而是由 Go 编译器先进行逃逸分析再进行分配
- 如果该变量退出函数后没有用了,就将其分配到栈上
 - 反之,即使你表面上只是一个普通的变量,但是经过逃逸分析后发现在退出函数之后还有其他地方在引用,则分配到堆上。
 
 
实例
package main
func main(){
	x := f()
	print(x)
}
func f() *int{
	r := 1
	return &r
}
执行
go build -gcflags '-m -l' main.go
- -gcflags:垃圾回收参数
 - -l:不让参数内联
 
得到结果
r 从函数中逃逸了
也可以使用反汇编命令也可以看出变量是否发生逃逸。
go tool compile -S main.go
总结
- 
通过逃逸分析,可以尽量把不需要分配到堆上的变量分配到栈上。堆上的变量少了,会减轻分配堆内存的开销,也会减少gc的压力,提高程序的运行速度。
 - 
不要盲目使用变量的指针作为函数参数,虽然它会减少复制操作。但其实当参数为变量自身时,复制是在栈上完成的,开销远比变量逃逸后动态地在堆上分配内存少的多。
 - 
尽量写出少一些逃逸的代码,提升程序的运行效率。