- the heap contains values that are referenced outside of a function.
Go prefers to allocate memory on the stack, so most memory allocations will end up there. This means that Go has a stack per goroutine and when possible Go will allocate variables to this stack. The Go compiler attempts to prove that a variable is not needed outside of the function by performing ==escape analysis== to see if an object “escapes” the function.
https://medium.com/safetycultureengineering/an-overview-of-memory-management-in-go-9a72ec7c76a8
How do we know when a variable is allocated to the heap?
Go compilers will allocate variables that are local to a function in that function’s stack frame. However, if the compiler cannot prove that the variable is not referenced after the function returns, then the compiler must allocate the variable on the garbage-collected heap to avoid dangling pointer errors. Also, if a local variable is very large, it might make more sense to store it on the heap rather than the stack.
If a variable has its address taken, that variable is a candidate for allocation on the heap. However, a basic escape analysis recognizes some cases when such variables will not live past the return from the function and can reside on the stack.
https://go.dev/doc/faq#stack_or_heap
non-pointer Go values stored in local variables will likely not be managed by the Go GC at all, and Go will instead arrange for memory to be allocated that’s tied to the lexical scope in which it’s created.
Escape to the heap
Go values whose memory cannot be allocated this way, because the Go compiler cannot determine its lifetime, are said to escape to the heap.
There are many reasons why a Go value might need to escape to the heap. One reason could be that its size is dynamically determined. Consider for instance the backing array of a slice whose initial size is determined by a variable, rather than a constant. Note that escaping to the heap must also be transitive: if a reference to a Go value is written into another Go value that has already been determined to escape, that value must also escape.
Whether a Go value escapes or not is a function of the context in which it is used and the Go compiler’s escape analysis algorithm. It would be fragile and difficult to try to enumerate precisely when values escape: the algorithm itself is fairly sophisticated and changes between Go releases. For more details on how to identify which values escape and which do not, see the section on eliminating heap allocations.
Since compiler implementations change over time, there’s no way of knowing which variables will be allocated to the heap simply by reading Go code. It is, however, possible to view the results of the *escape analysis *mentioned above in output from the compiler. This can be achieved with the gcflagsargument passed to go build. A full list of options can be viewed via go tool compile -help.
go build -gcflags '-m -l'