Memory allocation difference between slice and array

I did the escape analysis of the following code.

package main

func main() {
    u := make([]int, 8191) // Does not escape to heap
    _ = u

    v := make([]int, 8192) // Escapes to heap = 64kb
    _ = v

    var w [1024 * 1024 * 1.25]int
    _ = w

    var x [1024 * 1024 * 1.25+1]int // moved to heap > 10 mb
    _ = x
}

The output of the escape analysis is as follows

./main.go:3:6: can inline main
./main.go:13:6: moved to heap: x
./main.go:4:11: main make([]int, 8191) does not escape
./main.go:7:11: make([]int, 8192) escapes to heap

When slice size hits 64 KB, its memory allocation is on the heap. But when array size goes beyond 10 mb then it is moved to heap.

Why Golang waits for array size to go beyond 10 MB before moving to heap while same does not apply to slice?

1 Like

:+1: That’s very interesting; I’m interested to see if someone else knows the answer! I’ll check out the Go source code to see if I can find out.

EDIT: I give up; I need to learn more about compiler backends before I’d be able to find this out.

1 Like

@snanurag Found it: src/cmd/compile/internal/gc/go.go. The difference between maxStackVarSize and maxImplicitStackVarSize

Thank you Sean. That was helpful. Do you also have any idea stack allocation is so high for explicit variables?

I don’t know why, but I can speculate:

  1. Stack allocation is computationally easier to manage, so it is favored over the heap if possible. Cleaning up a stack frame can be as simple as popping the top of the stack into the CPU’s program counter whereas a heap allocation requires the garbage collector to track and follow pointers.

  2. Based on my skim through the escape analysis code, the significant distinction between values and pointers seems to just be their semantics. A pointer variable might be backed by a stack-allocated value and a value variable might actually live in the heap. The difference is just the language semantics and the way the runtime of the Go reference implementation optimizes them.

    If you want a large value to be on the stack, you “hint” that to the compiler by making it an explicit value variable. It will still escape to the heap if it has to, but that’s the way you signal your intention to the compiler. Same with how p := new(int) signals that p might escape to the heap (if it doesn’t need to be on the heap, why new it?), but the compiler might optimize it to a local variable if it can prove that it can while keeping the program correct and memory-safe.

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.