一句话定义
分段栈和连续栈是 Go 语言在不同阶段采用的栈内存组织方式。分段栈通过链表连接多个内存块,而连续栈则通过整体拷贝来维持单一的连续内存空间。
核心原理
1. 分段栈 (Segmented Stacks)
这是 Go 1.3 之前的方案。
- 工作方式:当当前栈空间不足时,Runtime 会分配一块新的内存段,并用指针将旧段和新段连接起来(类似链表)。
- 优点:扩容非常快,只需要分配一小块内存并挂载即可,不需要拷贝数据。
- 致命缺点:热分裂 (Hot Split)。如果一个函数调用恰好发生在栈容量的边缘,且处于循环中,程序会频繁地申请新段、释放新段,产生巨大的性能开销。
2. 连续栈 (Continuous Stacks)
这是 Go 1.3 之后至今的方案。
- 工作方式:当空间不足时,Runtime 会分配一块两倍于原栈的新内存,将旧栈内容整体拷贝过去,并释放旧栈(类似 ArrayList 的扩容)。
- 优点:
- 彻底解决了热分裂问题。
- 栈上数据在物理内存上是连续的,利用了 CPU 缓存局部性,访问速度更快。
- 核心挑战:必须修正所有指向旧栈的指针。Go 通过在编译期生成的栈图 (Stack Map) 精确识别指针位置,从而安全地完成地址更新。
应用场景
- 现代 Go 运行时:默认采用连续栈,确保了即使在复杂的嵌套调用下,性能依然稳定。
- 高性能并发:连续栈的局部性优势使得 Goroutine 在处理密集计算时比分段栈更具优势。
知识扩展
- 热分裂 (Hot Split):分段栈特有的性能陷阱。
- 栈图 (Stack Map):连续栈能够实现“指针修正”的技术前提。
- ArrayList 扩容机制:连续栈在设计思想上与之非常相似。