面试题答案
一键面试逃逸分析与栈空间分配策略
- 函数调用底层原理:在Go语言中,函数调用时会在栈上创建一个栈帧,用于存储函数的局部变量、参数和返回值等信息。栈帧的大小在编译时就已确定。当函数调用结束,栈帧会被销毁,其所占空间被释放。
- 逃逸分析对栈空间分配的影响:逃逸分析通过分析变量的作用域和生命周期,判断变量是否会在函数返回后继续被使用。如果变量不会逃逸,编译器会将其分配在栈上,因为栈上分配和释放效率高;如果变量逃逸,编译器会将其分配在堆上,堆空间由垃圾回收器管理,分配和释放相对复杂。
变量发生逃逸的情况及影响
- 返回局部变量指针:
package main func createString() *string { s := "hello" return &s }
- 逃逸分析:这里变量
s
发生逃逸。因为函数返回了s
的指针,在函数返回后,这个指针可能被其他地方使用,所以s
不能在栈上分配,必须分配在堆上。 - 对栈和堆的影响:栈空间不会为
s
分配,减少了栈帧大小。s
被分配在堆上,增加了堆的使用,垃圾回收器需要管理s
的生命周期。
- 逃逸分析:这里变量
- 闭包引用局部变量:
package main func closure() func() int { num := 10 return func() int { return num } }
- 逃逸分析:变量
num
发生逃逸。闭包会持有num
的引用,即使closure
函数返回,闭包仍可能使用num
,所以num
要分配在堆上。 - 对栈和堆的影响:栈上不分配
num
的空间,栈帧变小。num
分配在堆上,堆使用量增加,GC 需管理其生命周期。
- 逃逸分析:变量
- 将局部变量作为参数传递给可能跨函数边界的函数:
package main var globalFunc func() func passFunc(f func()) { globalFunc = f } func test() { localVar := 5 passFunc(func() { print(localVar) }) }
- 逃逸分析:
localVar
发生逃逸。因为localVar
被传递给passFunc
并在匿名函数中使用,且globalFunc
可能在test
函数返回后调用,所以localVar
要分配在堆上。 - 对栈和堆的影响:栈上不为
localVar
分配空间,减少栈帧大小。localVar
分配在堆上,增加堆使用,由 GC 管理其生命周期。
- 逃逸分析: