内存逃逸是由编译器来决定内存分配的位置(是在栈上还是在堆上分配内存),而不是由程序员来决定的! 在函数中申请一个新的对象:
1、如果分配在栈中,则函数执行结束后可自行将内存回收
2、如果分配在堆中,则函数执行结束后可交给GC(垃圾回收)处理。
内存逃逸场景
1、指针逃逸
我们知道Go可以返回局部变量指针,这其实是一个典型的变量逃逸案例。
type Student struct {
Name string
}
func Say() *Student {
stu := Student{}
stu.Name = "张三"
return &stu
}
2、栈空间不足逃逸
很多函数的参数为interface 类型,比如 fmt.Println(a ...interface{}),编译期间很难确定其参数的具体类型,也会产生逃逸
func slice() {
s := make([]int, 10000, 10000)
for index, _ := range s {
s[index] = index
}
}
3、动态类型逃逸
s := "sbc"
fmt.Println(s)
4、闭包引用对象逃逸
func bibao() func() int {
a, b := 0, 1
return func() int {
a, b = b, a+b
return a
}
}
该函数返回一个闭包,闭包引用了函数的局部变量a和b,使用时通过该函数获取闭包,a,b只能放到堆中,所以产生了逃逸。
小结:
栈上分配内存比在堆中分配内存有更高的效率;
栈上分配的内存不需要GC处理;
逃逸分析的目的是决定分配地址是栈还是堆;
逃逸分析在编译阶段完成;