试图检查是否在go程序中的堆或堆栈上分配了局部变量,并且不能确定go的gc的某些输出的含义。
variable_heap_stack.go:
// variable heap & stack learn,
// run with:
// go run -gcflags -m xxx.go
package main
import "fmt"
func getPointerOfLocalVar() *int {
x := 10 // go will put it into heap,
return &x
}
// heap & stack test,
func heapStackTest() {
px := getPointerOfLocalVar()
fmt.Printf("x: %d\n", *px)
y := 20 // go will put it into stack,
fmt.Printf("y: %d\n", y)
}
func main() {
heapStackTest()
}
执行:
运行-gcflags -m variable_heap_stack.go
输出:
# command-line-arguments
./variable_heap_stack.go:8:6: can inline getPointerOfLocalVar
./variable_heap_stack.go:15:28: inlining call to getPointerOfLocalVar
./variable_heap_stack.go:10:9: &x escapes to heap
./variable_heap_stack.go:9:6: moved to heap: x
./variable_heap_stack.go:16:24: *px escapes to heap
./variable_heap_stack.go:19:13: y escapes to heap
./variable_heap_stack.go:15:28: heapStackTest &x does not escape
./variable_heap_stack.go:16:12: heapStackTest ... argument does not escape
./variable_heap_stack.go:19:12: heapStackTest ... argument does not escape
x: 10
y: 20
escapes to heap
是什么意思?是否会堆积?moved to heap
,这意味着转移到堆,对不对?与上面的有什么区别?y
变量是局部变量,函数返回后没有人引用它,但是仍然有一行y escapes to heap
,为什么?答案 0 :(得分:1)
escapes to heap
是什么意思?会不会堆积?
这意味着消息消息中指示的值会释放函数的“边界” ,因此,不能保证函数外部会发生什么,因此,如果该值是指针或引用(但仅限于此),必须在堆上分配指向或引用的值。
您可以将escapes to heap
视为一条调试消息,它并不表示您的变量之一已“重定位”到堆中。
因此,简单来说,“转义为堆” 类似于术语:“它离开了函数” 或”它被传递到外部的功能” 。
例如,此行:
./variable_heap_stack.go:16:24: *px escapes to heap
表示将值*px
传递到函数外部,即作为此行中fmt.Printf()
的参数:
fmt.Printf("x: %d\n", *px)
moved to heap
,这意味着转移到堆,对不对?与上面的有什么区别?
这表明编译器决定将消息中指示的变量移至堆,因为它可能在函数外部被引用,因此它必须在函数中保留下来。而且,由于一旦您从函数返回后,分配给堆栈的值可能会变得无效,因此要使指示的变量在函数返回后有效,就必须在堆上。
Moved to heap
是一个直接声明,您的变量中的一个确实已“重定位”到堆中。注意:“ relocated”意味着变量将被分配到堆中的变量中。首先,在任何情况下都不会发生实际的“重定位”。
y
变量是局部变量,函数返回后没有人引用它,但是仍然有一行y escapes to heap
,为什么?
如前所述,这并不意味着将y
重定位到堆,而只是意味着将值y
传递到函数之外,即作为参数fmt.Printf()
行:
fmt.Printf("y: %d\n", y)
y
不会仅仅因为这个原因而移到堆中,没有必要,因为它是通过复制其值传递给fmt.Printf()
的,而fmt.Printf()
将具有无法访问您的y
局部变量。
提示:
您可以通过两次两次-m
来获得有关优化决策和转义分析的更多详细信息:
go run -gcflags='-m -m' variable_heap_stack.go
然后此命令的输出将是:
./variable_heap_stack.go:8:6: can inline getPointerOfLocalVar as: func() *int { x := 10; return &x }
./variable_heap_stack.go:14:6: cannot inline heapStackTest: non-leaf function
./variable_heap_stack.go:15:28: inlining call to getPointerOfLocalVar func() *int { x := 10; return &x }
./variable_heap_stack.go:22:6: cannot inline main: non-leaf function
./variable_heap_stack.go:10:9: &x escapes to heap
./variable_heap_stack.go:10:9: from ~r0 (return) at ./variable_heap_stack.go:10:2
./variable_heap_stack.go:9:2: moved to heap: x
./variable_heap_stack.go:16:24: *px escapes to heap
./variable_heap_stack.go:16:24: from ... argument (arg to ...) at ./variable_heap_stack.go:16:12
./variable_heap_stack.go:16:24: from *(... argument) (indirection) at ./variable_heap_stack.go:16:12
./variable_heap_stack.go:16:24: from ... argument (passed to call[argument content escapes]) at ./variable_heap_stack.go:16:12
./variable_heap_stack.go:19:13: y escapes to heap
./variable_heap_stack.go:19:13: from ... argument (arg to ...) at ./variable_heap_stack.go:19:12
./variable_heap_stack.go:19:13: from *(... argument) (indirection) at ./variable_heap_stack.go:19:12
./variable_heap_stack.go:19:13: from ... argument (passed to call[argument content escapes]) at ./variable_heap_stack.go:19:12
./variable_heap_stack.go:15:28: heapStackTest &x does not escape
./variable_heap_stack.go:16:12: heapStackTest ... argument does not escape
./variable_heap_stack.go:19:12: heapStackTest ... argument does not escape
x: 10
y: 20