The code:
func MaxSmallSize() {
a := make([]int64, 8191)
b := make([]int64, 8192)
_ = a
_ = b
}
Then run go build -gcflags='-m' . 2>&1 to check memory allocation details. The result:
./mem.go:10: can inline MaxSmallSize
./mem.go:12: make([]int64, 8192) escapes to heap
./mem.go:11: MaxSmallSize make([]int64, 8191) does not escape
My question is why a is small object and b is large object?
make 64KB will escape to heap and less will allocate in stack. Does the _MaxSmallSize = 32 << 10 is the reason?
go env
GOARCH="amd64"
GOBIN=""
GOEXE=""
GOHOSTARCH="amd64"
GOHOSTOS="linux"
GOOS="linux"
GOPATH="/vagrant/gopath"
GORACE=""
GOROOT="/home/vagrant/go"
GOTOOLDIR="/home/vagrant/go/pkg/tool/linux_amd64"
CC="gcc"
GOGCCFLAGS="-fPIC -m64 -pthread -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build201775001=/tmp/go-build"
CXX="g++"
CGO_ENABLED="1"
Since this is not mentioned in the language spec, it is an implementation detail, and as such, it may vary based on a number of things (Go version, target OS, architecture etc.).
If you want to find out its current value or a place to start digging, check out the
cmd/compile/internal/gcpackage.The escape analysis which decides where to allocate the variable is in
cmd/compile/internal/gc/esc.go. Check of the make slice operation is in unexported functionesc():The decision involving the size is in function
isSmallMakeSlice(), this is in filecmd/compile/internal/gc/walk.go:The size limit is this:
ris the length or capacity of the slice (if cap is provided),t.Elem().Widthis the byte size of the element type:In your case:
So if the slice type is
[]uint64, 8192 is the limit from which it is allocated on the heap (instead of the stack), just as you experienced.