逃逸分析(Escape analysis)是指由编译器决定内存分配的位置,不需要程序员指定。 函数中申请一个新的对象如果分配在栈中,则函数执行结束可自动将内存回收;如果分配在堆中,则函数执行结束可交给GC(垃圾回收)处理;
每当函数中申请新的对象,
编译器会跟据该对象是否被函数外部引用来决定是否逃逸:
1. 如果函数外部没有引用,则优先放到栈中;
2. 如果函数外部存在引用,则必定放到堆中.
注意,但然上述表述不是绝对的,对于函数外部没有引用的对象,也有可能放到堆中,比如内存过大超过栈的存储能力。

逃逸检测

当前检测版本

  1. g$ go version
  2. go version go1.13.9 darwin/amd64
  1. package main
  2. import "fmt"
  3. func bar()int{
  4. t :=2
  5. return t
  6. }
  7. func main() {
  8. x :=bar()
  9. fmt.Println(x)
  10. y :=x+1
  11. fmt.Println(y)
  12. }

执行函数

  1. # command-line-arguments
  2. ./main.go:11:13: main ... argument does not escape
  3. ./main.go:11:13: x escapes to heap
  4. ./main.go:13:13: main ... argument does not escape
  5. ./main.go:13:13: y escapes to heap

main函数里的x也逃逸了?这是因为有些函数参数为interface类型,比如fmt.Println(a …interface{}),编译期间很难确定其参数的具体类型,也会发生逃逸。
使用反汇编命令也可以看出变量是否发生逃逸。

  1. go tool compile -S main.go

逃逸分析通常有四种情况:

  • 指针逃逸
  • 栈空间不足逃逸
  • 动态类型逃逸
  • 闭包引用对象逃逸

    逃逸总结

  • 栈上分配内存比在堆中分配内存有更高的效率.

  • 栈上分配的内存不需要GC处理.
  • 堆上分配的内存使用完毕会交给GC处理.
  • 逃逸分析目的是决定内分配地址是栈还是堆.
  • 逃逸分析在编译阶段完成.