Heap and stack in Go

Heap and stack

Concept of memory allocation

Firstly, let's get familiar with the concept of memory allocation. If you're building a program, every variable you declare needs to be stored somewhere in the memory. Each language has its own way of allocating memory. In Go, variable can be stored either within the function's stack frame or in the heap.

Difference between stack and heap

The stack is a faster way to allocate and deallocate memory, because items are stored there in a LIFO (last in, first out) order, but it's limited in size (in Go 1.21 minimum stack size is 2048 bytes, maximum 1GB). On the other hand, the heap is slower, but it's not limited in size. It's important to know that the heap is managed by the garbage collector, so it's not possible to manually deallocate memory from the heap.

Memory allocated to the function's stack frame is 'living' next to go routine. It means that if you declare a variable in the function, compiler will try to allocate memory for this variable in the stack frame (if it's possible).

How memory allocation works in Go

In previous section I've mentioned that compiler will allocate memory in the stack frame if it's possible. But what does it mean? It means that if the compiler cannot prove that variable is not reference after function returns then it has to move it to the heap where garbage collector will take care of it. Are there any other cases when compiler will allocate memory in the heap? Yes, there are. Here are some of them:

  1. when compiler will decide that value is too large to live on the stack
  2. when a value is or could possibly be referenced somewhere else (outside of that function) after the function returns
  3. if compiler is not able to determine to size of the value while compiling code, so let's say we have a slice that's size will differ depend on external conditions Some examples are:
  4. values that are shared with pointers
  5. variables stored in interface variables
  6. values capture by clousure
  7. backing data for maps, channels, slices, strings

Do I need to know where my variable is allocated?

From Go documentation: Stack or heap?
How do I know whether a variable is allocated on the heap or the stack? From a correctness standpoint, you don't need to know. Each variable in Go exists as long as there are references to it. The storage location chosen by the implementation is irrelevant to the semantics of the language. When possible, the 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