golang程序变量会携带油一组校验数据,用来证明它的整个生命周期是否在运行时完全可知。如果变量通过了这些校验,它就可以在栈上分配。否则就说它逃逸了,必须在堆上分配
能引起变量逃逸到堆上的典型情况:
1.在方法内把局部变量指针返回
局部变量原本应该在栈中分配,在栈中回收。但是由于返回时被外部引用,因此其生命周期大于栈,则溢出
2.发送指针或带有指针的值到channel中
在编译时,是没有办法知道那个goroutine会在channel上接收数据。所以编译器没法知道变量什么时候才会被释放
3.在一个切片傻姑娘存储指针或带指针的值
一个典型的例子就是[]*string.这会导致切片的内容逃逸,尽管其后面的数组可能是在栈上分配的,但其引用的值一定是在堆上
4.slice的背后数组被重新分配了,因为append时可能会超出其容量
slice初始化的地方在编译时是可以知道的,它最开始在栈上分配,如果切片背后的存储要基于运行时的数据进行扩充,就会在堆上分配
5.在interface类型上调用方法
在interface类型傻姑娘调用方法都是动态调度的——方法的真正实现只能在运行时知道。想象一个io.Reader类型的变量r,调用r.Read(b)会使得r的值和切片b的背后存储都逃逸掉,所以会在堆上分配