Golang栈空间管理

分段栈

在Go1.3之前,所有goroutine在初始化时都会分配一块固定大小的内存空间。

  • 在固定8KB或者满足其他条件下,会在全局的栈缓存链表中找到空闲的内存块作为新goroutine的栈空间返回
  • 其余情况,会在堆上申请一块合适的内存

所有栈空间会以链表的形式串联起来

分段栈能够按需为当前goroutine分配内存,并及时减少内存占用,但

  • 如果当前goroutine栈几乎充满,那么任意的函数调用都会触发栈扩容,当函数返回后又会触发栈的收缩,如果在一个循环中调用函数,栈的分配和释放就会造成巨大的额外开销,这被称为热分裂问题(Hot split)
  • 一旦 Goroutine 使用的内存越过了分段栈的扩缩容阈值,运行时会触发栈的扩容和缩容,带来额外的工作量

连续栈

连续栈核心原理是当当前栈内存不足时,会触发中断,从而分配更大充足的栈空间,并迁移原栈内容到新栈

迁移过程会被指针也同样迁移过来,不过没关系根据逃逸分析不变性——指向栈对象的指针不能存在于堆中,所以指向栈中变量的指针只能在栈上

与堆类似,栈也有全局和局部栈空间

  • 全局栈空间
    • runtime.stackpool(全局栈缓存):分配小于32KB
    • runtime.stackLarge(全局大栈缓存):分配大于32KB。如果空间不足会在堆上申请
  • 线程缓存:分配小于32KB

此外,除了扩容,连续栈还会在已使用的栈空间未超过了总可用空间的四分之一,将新栈收缩到原来的一半

Ref

  1. https://draveness.me/golang/docs/part3-runtime/ch07-memory/golang-stack-management/

你可能感兴趣的:(io,lang,golang,开发语言,后端)