0. 简介
前面我们分别介绍了堆空间管理的内存分配器和垃圾收集,这里我们简单介绍一下Go中栈空间的管理。
1. 系统栈和Go栈
1.1 系统线程栈
pthread_create8192KB
对于栈上的内存,程序员无法直接操作,由系统统一管理,一般的函数参数、局部变量(C语言)会存储在栈上。
1.2 Go栈
runtime
Go语言使用用户态协程goroutine作为执行的上下文,其使用的默认栈大小比线程栈高的多,其栈空间和栈结构也在早期几个版本中发生过一些变化:
- v1.0 ~ v1.1 — 最小栈内存空间为 4KB;
- v1.2 — 将最小栈内存提升到了 8KB;
- v1.3 — 使用连续栈替换之前版本的分段栈;
- v1.4 — 将最小栈内存降低到了 2KB;
2. 栈操作
runtime.stack[lo, hi)
栈的结构虽然非常简单,但是想要理解 Goroutine 栈的实现原理,还是需要我们从编译期间和运行时两个阶段入手:
cmd/internal/obj/x86.stacksplitruntime.morestackruntime.morestack_noctxtruntime.malgruntime.stackallocruntime.morestack
//go:nosplit
2.1 栈初始化
stackpoolstackLarge
其初始化函数如下,从下也可以看出,Go栈的内存都是分配在堆上的:
2.2 栈分配
_FixedStack = 2048_NumStackOrders = 4_StackCacheSize = 32768
runtime.stackLarge
2.3 栈扩容
cmd/internal/obj/x86.stacksplitruntime.morestackruntime.newstack
在此期间可能触发抢占。
接下来就是分配新的栈内存和栈拷贝,这里就不详细描述了。
2.4 栈缩容
runtime.shrinkstack
2KB
1/4runtime.copystack