[Go] Stack or heap(2): slices which keep in stack have limitation of size

Yu-Lang Chu
2 min readJul 4, 2019

--

Photo by Viktor Theo on Unsplash

Variables in stack must have limit, otherwise stack overflow will happen often. Go compiler will choose heap or stack for slice not only by scope, but also depends on size. Let’s write down some code:

Here is benchmark result and escape analysis

./slice_large_sync-pool_test.go:10:49: Benchmark_LargeSize_Stack_EqualOrLess65535 b does not escape
./slice_large_sync-pool_test.go:13:20: Benchmark_LargeSize_Stack_EqualOrLess65535 make([]byte, size - 1) does not escape
./slice_large_sync-pool_test.go:20:20: make([]byte, size) escapes to heap
./slice_large_sync-pool_test.go:17:47: Benchmark_LargeSize_Heap_LargerThan65535 b does not escape

You can see in these two tests, the memory size of slice has only 1 byte different, but small one slice keeps in stack and another escapes to heap.

The source code could be found in the following code block of GO GC

section of esc function in esc.go

There is a isSmallMakeSilce function to check the size of slice. This function locates in walk.go

maxImplicitStackVarSize constant is to calculate the limitation. It is declared in go.go

simple examples how it works:

For []int64:
maxImplicitStackVarSize/t.Elem().width = 65536/8(int64) = 8192
so, make([]int64, 8192) will escape to heap
For []byte:
maxImplicitStackVarSize/t.Elem().width = 65536/1(byte) = 65536
so, make([]byte, 65536) will escape to heap

TL;DR :

Declare size of slice by requirement. Large size slice will escape to heap. But generally speaking , slice is used for dynamically-sized and flexible, to be careful for the size is not necessary. Here just shows something behind the scenes of Garbage Collector.

--

--