Go: How Does the Goroutine Stack Size Evolve?

Vincent
A Journey With Go
Published in
8 min readJun 1, 2019

--

Illustration created for “A Journey With Go”, made from the original Go Gopher, created by Renee French.

ℹ️ This article is based on Go 1.12.

Go provides a light and smart goroutines management. Light because the goroutine stack starts at 2Kb only, and smart since goroutines can grow / shrink automatically according to our needs.

Regarding the size of the stack, we can find it in runtime/stack.go :

// The minimum size of stack used by Go code
_StackMin = 2048

We should note that it has evolved through the time:

  • Go 1.2: goroutine stack has been increased from 4Kb to 8Kb.
  • Go 1.4: goroutine stack has decreased from 8Kb to 2Kb.

The stack size has moved due to the strategy of the stack allocation. We will go back to this topic later in this article.

This default stack size is sometimes not enough to run our program. This is when Go automatically adjusts the size of the stack.

Dynamic stack size

If Go can automatically grow the size of the stack, it is also able to determine that the allocation size will not have to change. Let’s take an example and analyze how it works:

func main() {
a := 1
b := 2

r := max(a, b)
println(`max: `+strconv.Itoa(r))
}

func max(a int, b int) int {
if a >= b {
return a
}

return b
}

This first example just calculates the higher number among 2 integers. In order to know how Go manages the allocation of the goroutine’s stack, we can look at the Go’s assembler code with the command: go build -gcflags -S main.go. The output — I just left the lines that are related to the stack allocation — give us some interesting lines that can show what Go is doing:

"".main STEXT size=186 args=0x0 locals=0x70
0x0000 00000 (/go/src/main.go:5) TEXT "".main(SB), ABIInternal, $112-0
[...]
0x00b0 00176 (/go/src/main.go:5) CALL runtime.morestack_noctxt(SB)
[...]0x0000 00000 (/go/src/main.go:13) TEXT "".max(SB), NOSPLIT|ABIInternal, $0-24

There are two instructions that involves the stack changes:
- CALL runtime.morestack_noctxt: this method will increase the size of the stack if it needs more.
-NOSPLIT: this…

--

--