我对 Go 的堆栈管理感兴趣。我搜索了各种数据,但它让我感到困惑,因为所有数据都不同。我比较好奇的是,golang 的栈管理是栈拆分还是栈复制。
正确答案是什么?
golang 版本:go1.16.3
堆栈拆分与堆栈复制与其说是一种语言特性——语言规范都没有提到任何一种策略——因为它是语言实现中的一种设计选择,其中有几种。因此,正如 Flimzy 在他的评论中指出的那样,您应该指定您在问题中指的是哪个实现。
从Go 1.4 开始,“规范的”Go 编译器(称为gc)不再拆分堆栈,现在使用堆栈复制:
堆栈现在是连续的,必要时重新分配而不是链接新的“段”;因此,此版本消除了臭名昭著的“热堆栈拆分”问题。
Brad Fitzpatrick(Go 团队的前成员)在他的 Gophercon India 2016(标记为 12'50'')中解释了 Go 编译器中堆栈拆分导致的一些问题:
[...] 在 Go 中,你有 goroutines,它就像一个非常非常轻量级的线程,它有一个很小的堆栈,并且可以根据需要增长。它过去的工作方式是使用小堆栈的小 goroutine,当你用完堆栈空间时,你会在其他地方创建另一个堆栈,当你调用函数并返回时,你会在这些堆栈之间跳转。大多数时候这很好,直到它不是,直到你处于一个紧凑的循环中,在像 JPEG 解码器之类的东西中,你在堆栈之间跳来跳去,你有非常大的性能损失,我们感到惊讶。然后你将一些代码移到其他地方,你的性能特征会发生很大变化。
至于gccgo(Go 语言的另一种实现),Ian Lance Taylor 解释说它在2016 年的线程中使用了堆栈拆分;Keith Randall 还在另一个帖子中提供了有关此设计选择的一些见解。