How do you inspect escape analysis decisions, and how do you read the output?
Build with go build -gcflags='-m' ./.... Use -m -m for the reason chain behind each decision, and -gcflags='-m -l' to turn off inlining so the output is easier to follow.
package main
import "fmt"
type Point struct{ X, Y int }
func NewPoint(x, y int) *Point { return &Point{x, y} }
func Sum(xs []int) (s int) {
for _, v := range xs {
s += v
}
return
}
func main() {
p := NewPoint(1, 2)
fmt.Println(p.X, Sum([]int{1, 2, 3}))
}
Output (Go 1.25, gofmt'd file with tab indentation):
./main.go:7:6: can inline NewPoint
./main.go:9:6: can inline Sum
./main.go:17:15: inlining call to NewPoint
./main.go:18:22: inlining call to Sum
./main.go:18:13: inlining call to fmt.Println
./main.go:7:41: &Point{...} escapes to heap
./main.go:9:10: xs does not escape
./main.go:17:15: &Point{...} does not escape
./main.go:18:13: ... argument does not escape
./main.go:18:15: p.X escapes to heap
./main.go:18:22: s escapes to heap
./main.go:18:28: []int{...} does not escape
Notice that &Point{} escapes inside NewPoint but not in main. Once NewPoint is inlined, the compiler can see the pointer never leaves main. Inlining is what makes small constructors cheap. "moved to heap: x" means a named variable was heap-allocated. "leaking param: p" means the parameter flows out of the function, for example into a return value or a global. "p.X escapes to heap" and "s escapes to heap" refer to the int values being boxed into any for fmt.Println. Values 0-255 use static data, so no allocation actually happens at run time here.
More on Memory, GC & Runtime Internals
- Q331How does Go decide whether a variable lives on the stack or the heap?
- Q333List the common reasons a value escapes to the heap.
- Q334How do goroutine stacks grow, and why does that constrain the language?
- Q335Describe Go's memory allocator: size classes, mcache/mcentral/mheap, and the tiny allocator.
- Q336Explain Go's concurrent tri-color mark-and-sweep garbage collector.
- Q337What is a write barrier and which one does Go use?