'go run -gcflags -m xxx.go' 的输出是什么意思
What is the meaning of the output from 'go run -gcflags -m xxx.go'
在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()
}
执行:
go run -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
变量是局部变量,在函数returns之后没有人引用它,但是还有一行y escapes to heap
,这是为什么?
What does escapes to heap
mean? Is it going to heap or not?
这意味着消息中指示的值 离开了函数的 "boundaries",因此,无法保证它在函数外部会发生什么, 因此如果该值是指针或引用(但仅限于此),则必须在堆上分配指向或引用的值。
你可以把escapes to heap
当成调试信息,它并不表示你的一个变量"relocated"到堆
简单来说,"escapes to heap" 类似于术语:"it leaves the function",或 "it is passed outside of the function".
例如这一行:
./variable_heap_stack.go:16:24: *px escapes to heap
表示值 *px
被传递到函数外部,即作为参数传递给 fmt.Printf()
这一行:
fmt.Printf("x: %d\n", *px)
moved to heap
, this means move to heap, right? What's the difference with the above one?
这表明编译器决定将消息中指示的变量移动到堆中,因为它可能在函数外部被引用,因此它必须在函数中存活。并且由于从函数 return 后堆栈分配的值可能会变得无效,要使指示的变量在函数 return 之后有效,它必须在堆上。
Moved to heap
是直接声明你的一个变量确实"relocated"到堆。注:"relocated"表示变量将首先分配在堆上,实际 "relocation" 无论如何都不会发生。
The y
variable is local, no one refer to it after function returns, but there still got a line y escapes to heap
, why was that?
如前所述,这并不意味着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
在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()
}
执行:
go run -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
变量是局部变量,在函数returns之后没有人引用它,但是还有一行y escapes to heap
,这是为什么?
What does
escapes to heap
mean? Is it going to heap or not?
这意味着消息中指示的值 离开了函数的 "boundaries",因此,无法保证它在函数外部会发生什么, 因此如果该值是指针或引用(但仅限于此),则必须在堆上分配指向或引用的值。
你可以把escapes to heap
当成调试信息,它并不表示你的一个变量"relocated"到堆
简单来说,"escapes to heap" 类似于术语:"it leaves the function",或 "it is passed outside of the function".
例如这一行:
./variable_heap_stack.go:16:24: *px escapes to heap
表示值 *px
被传递到函数外部,即作为参数传递给 fmt.Printf()
这一行:
fmt.Printf("x: %d\n", *px)
moved to heap
, this means move to heap, right? What's the difference with the above one?
这表明编译器决定将消息中指示的变量移动到堆中,因为它可能在函数外部被引用,因此它必须在函数中存活。并且由于从函数 return 后堆栈分配的值可能会变得无效,要使指示的变量在函数 return 之后有效,它必须在堆上。
Moved to heap
是直接声明你的一个变量确实"relocated"到堆。注:"relocated"表示变量将首先分配在堆上,实际 "relocation" 无论如何都不会发生。
The
y
variable is local, no one refer to it after function returns, but there still got a liney escapes to heap
, why was that?
如前所述,这并不意味着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