//go:noinline funcNewCat(name string, age int) *Cat { c := new(Cat) // c will excape to heap c.Name = name c.Age = age return c }
funcmain() { NewCat("Tom", 5) }
进行逃逸分析
1 2 3 4 5
$ go build -gcflags="-m" cat.go # command-line-arguments ./cat.go:16:6: can inline main ./cat.go:9:13: leaking param: name ./cat.go:10:10: new(Cat) escapes to heap
可以看到,./cat.go:10:10: new(Cat) escapes to heap, 有变量的内存逃逸。
动态类型逃逸
1 2 3 4 5 6 7 8 9 10 11 12
package main
import"fmt"
functest() *int { s := 3 return &s } funcmain() { x := test() fmt.Println(*x) }
编译代码
1 2 3 4 5
$ go build -gcflags="-m -l" dynamic.go # command-line-arguments ./dynamic.go:6:2: moved to heap: s ./dynamic.go:11:13: ... argument does not escape ./dynamic.go:11:14: *x escapes to heap
变量s产生了内存逃逸,正如前一个例子。 这里要注意的是,/dynamic.go:11:14: *x escapes to heap也发生了内存逃逸,这是因为fmt.Println(a ...interface{}),fmt接受的参数是interface{},这是类型不确定的。 编译期间不能确定参数的具体的类型,逃逸就会产生。
slice,map和channel的指针引用
1 2 3 4 5 6 7 8 9 10 11 12 13
package main
funcmain() { 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 }
编译代码
1 2 3 4 5 6
go run -gcflags "-m -l" main.go ./main.go:7:2: moved to heap: b ./main.go:11:2: moved to heap: d ./main.go:15:2: moved to heap: f ./main.go:6:11: main make([]*int, 1) does not escape ./main.go:10:11: main make(map[string]*int) does not escape
funcFibonacci()func()int { a, b := 0, 1 returnfunc()int { a, b = b, a+b return a } }
编译
1 2 3 4 5 6 7 8
$ go build -gcflags="-m" fib.go # command-line-arguments ./fib.go:5:9: can inline Fibonacci.func1 ./fib.go:4:2: moved to heap: a ./fib.go:4:5: moved to heap: b ./fib.go:5:9: funcliteralescapestoheap # command-line-arguments runtime.main_main·f: function main is undeclared in the main package
在Fibonacci()函数中,a,b是一个本地的变量,因为被闭包引用,所以被分配在了堆上。
栈容量不足
看下面的代码:
1 2 3 4 5 6 7 8 9
funcBigSlice() { s := make([]int, 1000, 1000) for index, _ := range s { s[index] = index } } funcmain() { BigSlice() }