一句话定义

Go 栈伸缩机制是 Go 运行时(Runtime)为每个 Goroutine 提供的自动内存调节方案,它让 Goroutine 能以极小的 2KB 启动,并根据函数调用深度自动“变大”或“缩小”。

核心原理

Go 采用的是 连续栈(Continuous Stacks) 方案。其核心逻辑在于:发现空间不足 开辟新空间 整体搬迁 更新地址

1. 自动扩容:应对深度调用

当函数执行发现栈空间即将触达“警戒线”时,会触发以下流程:

  • 检查(Stack Guard):编译器在函数开头埋下“哨兵”,发现栈顶快到了就呼叫 Runtime。
  • 搬家(Stack Copy):Runtime 找一块比原来大 2 倍的内存,把旧栈里的东西原样搬过去。
  • 修正指针:这是最难的一步。因为内存地址变了,Runtime 必须把栈上所有指向旧地址的指针,全部修改为指向新地址。

2. 自动缩容:回收闲置内存

为了不浪费内存,Go 不会在函数返回时立即缩容,而是在 GC(垃圾回收) 期间进行:

  • 触发条件:当栈的使用率低于 1/4 时。
  • 平滑策略:为了防止抖动,缩容后的新栈大小是原栈的 1/2(即使用率变为 1/2),且最小不低于 2KB。

应用场景

  • 高并发 Web 服务:支持百万级连接,因为每个连接(Goroutine)初始只占 2KB,内存压力极小。
  • 深度递归算法:开发者无需担心 Stack Overflow,只要内存够,栈就能一直长。

知识扩展

  • 逃逸分析:决定一个变量是待在“伸缩栈”上,还是去“公共堆”里。
  • 栈图 (Stack Map):Runtime 用来寻找并修正栈上指针的“地图”。
  • Stack Guard:每个 Goroutine 专属的“栈溢出”警戒线。