Go的栈空间管理

作者: simpleapples | 来源:发表于2018-10-11 18:42 被阅读0次

栈空间管理的基本逻辑

go语言通过goroutine提供了并发编程支持,goroutine是go运行库的功能,而不是操作系统线程实现的,goroutine可以被理解成一个用户态的线程。

既然goroutine是由go运行库管理的,那么go运行库也需要为每个goroutine创建并管理相应的栈空间,为每个goroutine分配的栈空间不能太大,goroutine开多时会浪费大量空间,也不能太小,会导致栈溢出。go语言选择栈的栈空间管理的方式是,一开始给一个比较小的空间,随着需要自动增长。当goroutine不需要那么大的空间时,栈空间也要自动缩小。

分段栈 Segment Stacks

在go 1.3之前,go使用分段栈。

分段栈实现了一种不连续但是可以持续增长的栈,开始时,栈只有一个段,当需要更多的栈空间时,会分配一个新的段,和上一个栈双向链接。这样,一个栈就是由多个双向链接的段所组成的。当新分配的段使用完毕后,新段会被释放掉。

分段栈实现了栈的按需收缩,在增加新分段时也不需要对原有分段中的数据进行拷贝,使得goroutine的使用代价非常低廉。

分段栈的好处是可以按需增长,空间利用率比较高,然而分段栈在某些情况下也存在一定的瑕疵。当一个段即将用尽,这时使用for循环执行一个比较耗空间的函数,会导致函数执行时goroutine进行段的分配,而执行完成返回时,进行段的销毁,这样就会导致在循环中出现多次栈的扩容和收缩,造成很大的性能损失,这种情况被称作栈分裂(Stack Split)。

连续栈 Contiguous Stacks

go 1.3推出了连续栈,连续栈使用了另外一种策略,不再把栈分成一段一段的,当栈空间不够时,直接new一个2倍大的栈空间,并将原先栈空间中的数据拷贝到新的栈空间中,而后销毁旧栈。这样当出现栈空间触及边界时,不会产生栈分裂的情况。

继续假设当前栈空间即将用尽,并且需要在for循环中执行一个比较消耗空间的函数。当该函数执行时,栈空间发生了扩容,变成原先2倍大小,函数执行完成一次后,栈空间的使用量缩小回执行前的大小,但是栈空间的使用量并没有小于栈大小的1/4,不会触发栈收缩,所以在整个for循环执行过程中,不会反复触发栈空间的收缩扩容。

总结

相比于分段栈,连续栈避免了某些场景下栈空间的的频繁伸缩。有一点需要注意的是,连续栈的收缩也是需要重新申请一段空间(原先的1/2大小),并进行栈拷贝操作的。

点击关注知乎专栏Golang私房菜

相关文章

  • Go的栈空间管理

    栈空间管理的基本逻辑 go语言通过goroutine提供了并发编程支持,goroutine是go运行库的功能,而不...

  • Go语言的栈空间管理

    翻译原文链接 转帖/转载请注明出处 英文原文链接 发表于2014/09/15 在CloudFlare,我们使用Go...

  • C语言内存管理

    存储区划分 栈区:在函数内部定义的局部变量和局部数组,都存在栈区,栈区空间由系统管理,函数调用时开辟空间,函数执行...

  • 005 go语言 两栈(双栈) 共享空间

    1 双栈共享空间 思路 如果有两个类型相同的栈,我们为它们分别开辟了数组空间。极有可能是一个栈已经满了,再入栈就溢...

  • 内存管理

    内存管理的原理? 内存空间总共有8块区域,有两个区域需要特别注意,一个就是堆空间,一个就是栈空间。栈里存放临时变量...

  • 优秀网站

    一.语言栈 GO go 博客 Go中国 zupzup : web Ewan : 微服务 go开源项目 Beego:...

  • Goroutine快速入门

    Go协程四大特点有独立的栈空间共享程序堆空间调度由用户控制协程是轻量级的线程 主线程和协程同时执行 如果主线程退出...

  • [libco] 协程栈空间

    协程“栈”空间,有独立栈和共享栈,重点理解一下协程共享栈。 文章来源:[libco] 协程栈空间[https://...

  • 第二章 内存管理

    2.1 内存消耗 2.1.1 栈大小1.每个线程都有专用的栈空间2.每个方法都有自己的栈帧,并消耗整体的栈空间,栈...

  • iOS 内存管理

    在介绍内存管理之前,先来简单了解一下内存中的堆和栈。 栈 当程序执行某个方法时,会从栈中分配一块内存空间,这块内存...

网友评论

    本文标题:Go的栈空间管理

    本文链接:https://www.haomeiwen.com/subject/onobaftx.html