2.6 简述一下 Go 栈空间的扩容/缩容过程? ======================================= 扩容流程 -------- **为啥会有栈空间扩容** 由于当前的 Go 的栈结构使用的是连续栈,并且初始值才 2k 比较小,因此随着函数的调用层级加深,Go 的初始栈空间就可能不够用,不够用的话,就会触发栈空间的扩容。 **栈空间扩容啥时会触发** 编译器会为函数调用插入运行时检查\ ``runtime.morestack``\ ,它会在几乎所有的函数调用之前检查当前\ ``goroutine`` 的栈内存是否充足,如果当前栈需要扩容,会调用\ ``runtime.newstack`` 创建新的栈。 而新的栈空间,是旧栈空间大小(通过保存在\ ``goroutine``\ 中的\ ``stack``\ 信息里记录的栈区内存边界计算出来的)的两倍,但最大栈空间大小不能超过 ``maxstacksize`` ,也就是 1G。 缩容流程 -------- **为啥会有栈空间缩容** 在函数返回后,对应的栈空间会回收,如果调用栈比较深,那么随着函数一个一个返回,回收的栈空间会越来越多。假设在调用栈最深的时候,整体的栈空间扩容到了 100M,那么随着函数的返回,到某一个函数的时候,100M 的栈空间只有 1M 是实际占用的,内存利用率只有区区的 1% ,实在太浪费了。 **栈空间缩容啥时会触发** 因此在垃圾回收的时候,有必要检查一下栈空间里内存利用率,当利用率低于 25% 时,就要开始进行缩容,缩容成原来的栈空间的 50%,但同时也不能小于栈空间的原始值即最小值,2KB。 相同点 ------ 不管是扩容还是缩容,都是使用 ``runtime.copystack`` 函数来开辟新的栈空间,然后将旧栈的数据全部拷贝至新的栈空间,并调整原来指针的指向。 延伸阅读 -------- `Go 语言内存管理三部曲(二)解密栈内存管理 `__