1 编译原理中,分析指针动态范围的方法称之为逃逸分析,Go语言的逃逸分析是编译器执行静态代码分析后,对内存管理进行的优化和简化,它可以决定一个变量是分配到堆还栈上。
go在编译的时候进行逃逸分析,来决定一个对象放栈上还是放堆上,不逃逸的对象放栈上,可能逃逸的放堆上。
编译器会根据变量是否被外部引用来决定是否逃逸:如果在函数外面没有引用到,则优先放到栈区中;如果在函数外面存在引用的可能,则就会放到堆区中;
//1 将变量取地址返回 //func test() *User{ // a := User{} // return &a //} //// 当输入的变量或指针,直接返回时,不会逃逸, //type S struct {} //func main() { // var x S // y := &x // _ = fun1(y) // _ = fun2(x) //} //// 输入直接当成返回值了,因为没有对z作引用,所以z没有逃逸 //func fun1(z *S) *S { // return z //} //func fun2(k S) S { // return k //} //// z是对x的拷贝,ref函数中对z取了引用,所以z不能放在栈上, //// 否则在ref函数之外,通过引用如何找到z,所以z必须要逃逸到堆上 //package main //type S struct {} //func main() { // var x S // _ = *ref(x) //} //func ref(z S) *S { // return &z //} // refStruct函数对y取了引用,所以y发生了逃逸,z没有逃逸, type S struct { M *int } func main() { var i int i = 2 refStruct(i) } // z不会逃逸,因为z是普通变量,返回z的时候是值拷贝, func refStruct(y int) (z S) { z.M = &y return z } // 这里的z会逃逸,因为返回的是指针,且z是内部开辟的内存, //func refStruct(y int) (z *S) { // z = new(S) // z.M = &y // return z //} // 这里的y没有逃逸,z也没有逃逸, //type S struct { // M *int //} //func main() { // var i int // refStruct(&i) //} //func refStruct(y *int) (z S) { // z.M = y // return z //} ////3 被指针类型的slice、map和chan引用的指针,注意必须是指针,一定发生逃逸 //func main() { // a := make([]*int,1) // b := 12 // a[0] = &b // // c := make(map[string]*int) // d := 14 // c["aaa"]=&d // // e := make(chan *int,1) // f := 15 // e <- &f //}
https://blog.csdn.net/dianfu2892/article/details/101467101
原文:https://www.cnblogs.com/xxswkl/p/14229446.html