简化您的示例。用进行分析
-gcflags='-m -m'。
范例1 :
package mainfunc main() { var v int s := make([]*int, 0) s = append(s, &v) // &v escapes to heap}输出:
$ go versiongo version devel +df8c2b905b Tue Mar 6 06:13:17 2018 +0000 linux/amd64$ go run -gcflags='-m -m' esc.go# command-line-arguments./esc.go:3:6: can inline main as: func() { var v int; v = <N>; s := make([]*int, 0); s = append(s, &v) }./esc.go:6:16: &v escapes to heap./esc.go:6:16: from append(s, &v) (appended to slice) at ./esc.go:6:12./esc.go:4:6: moved to heap: v./esc.go:5:11: main make([]*int, 0) does not escape$转义分析确定是否有任何对值的引用转义声明该值的函数。
v在函数中声明的对变量的引用
main作为函数的参数进行转义
append:
&vescapes to heap from append(s, &v),
moved to heap: v。
范例2 :
package mainfunc main() { var v int lc := 1 s := make([]*int, lc) s[0] = &v}$ go run -gcflags='-m -m' esc2.go./esc2.go:3:6: can inline main as: func() { var v int; v = <N>; lc := 1; s := make([]*int, lc); s[0] = &v }./esc2.go:6:11: make([]*int, lc) escapes to heap./esc2.go:6:11: from make([]*int, lc) (too large for stack) at ./esc2.go:6:11./esc2.go:7:9: &v escapes to heap./esc2.go:7:9: from s[0] (slice-element-equals) at ./esc2.go:7:7./esc2.go:4:6: moved to heap: v$type slice struct { array unsafe.Pointer len int cap int}make切片返回切片描述符
struct(指向基础数组,长度和容量的指针)并分配基础切片元素数组。底层数组通常在堆上分配:
make([]*int,lc) escapes to heap from make([]*int, lc)。
s[0] = &v存储对变量的引用
v(
&v)在堆上底层阵列中:
&v escapes to heap from s[0] (slice-element-equals),
moved to heap: v。函数结束并回收其堆栈之后,引用将保留在堆上,直到对基础数组进行垃圾回收为止。
如果
make切片容量是一个小的(编译时)常数,则
make([]*int,1)在您的示例中,基础数组可能会分配在堆栈上。但是,转义分析没有考虑到这一点。



