Trying to check whether a local variable is allocated on heap or stack in go program, and can't be sure the meaning of some output from go's gc.
Code
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()
}
Execute:
go run -gcflags -m variable_heap_stack.go
Output:
# 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
Questions
- What does
escapes to heapmean? Is it going to heap or not? moved to heap, this means move to heap, right? What's the difference with the above one?- The
yvariable is local, no one refer to it after function returns, but there still got a liney escapes to heap, why was that?
This means the value indicated in the message leaves the "boundaries" of the function, and as such, it cannot be guaranteed what happens with it outside of the function, so if the value is a pointer or reference (but only then), the pointed or referenced value must be allocated on the heap.
You can think of
escapes to heapas a debug message, it does not indicate that one of your variables is "relocated" to the heap.So to put it simple, "escapes to heap" is analogous to the term: "it leaves the function", or "it is passed outside of the function".
As an example this line:
Says that the value
*pxis passed outside of the function, namely as an argument tofmt.Printf()in this line:This indicates that the compiler decided to move the variable indicated in the message to the heap, because it might be referenced outside of the function, and thus it must survive the function. And since stack-allocated values may become invalid once you return from the function, for the indicated variable to be valid after the function returns, it must be on the heap.
Moved to heapis a direct announcement that one of your variables was indeed "relocated" to the heap. Note: "relocated" means that the variable will be allocated on the heap in the first place, actual "relocation" will not happen in any case.As mentioned before, this does not mean
yis relocated to heap, it only means the valueyis passed outside of the function, namely as a parameter tofmt.Printf()in this line:ywill not be moved to heap just because of this, there is no need, as it is passed tofmt.Printf()by making a copy of its value, andfmt.Printf()will have no way of reaching yourylocal variable.Note that since
fmt.Printf()expects a value of type...any, the variableywill be wrapped in an interface value, then in a slice, and wrapping it in an interface value is what causes the "escape". If you'd pass it to a function expectingintor even...int, no escape would happen as that would simply pass theintvalue without any reference or connection to theyvariable whatsoever.Tip:
You can get more details about optimization decisions and escape analysis by passing
-mtwice like this:Then the output of this command will be: