一句话定义

分段栈和连续栈是 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 扩容机制:连续栈在设计思想上与之非常相似。