为什么在make([] int,14)中有一个runtime.morestack但在make([] int,13)中没有?

时间:2019-02-01 08:46:42

标签: go runtime goroutine

我已经知道runtime.morestack将导致goroutine上下文切换(如果sysmon goroutine已将其标记为“必须切换”)。

当我对此做一些实验时,我发现了一个有趣的事实。

比较以下代码。

func main() {
    _ = make([]int, 13)
}

func main() {
    _ = make([]int, 14)
}

并通过运行以下命令进行编译:(在go1.9和go 1.11中进行了尝试

$ go build -gcflags "-S -l -N" x.go

您可能会发现一个主要区别是,第一个输出包含CALL runtime.morestack_noctxt(SB),而第二个不包含。

我想这是一个优化,但是为什么呢?

1 个答案:

答案 0 :(得分:2)

最后,我得到了答案。

  • 使少于65,536字节且未从func转义的切片将在堆栈而不是堆中分配。

  • StackGuard0将比堆栈的最低地址高至少128个字节。 (即使在缩小尺寸之后)

  • make([] int,13)将总共分配128个字节的内存。

  

sizeof(结构切片)+ 13 * 8 = 24 + 104 = 128。

因此答案很明确,这是对amd64的优化。

对于叶子函数,如果它使用的内存少于128个字节,则编译器不会生成检查堆栈是否溢出(因为有足够的空间)的代码。

这是go/src/runtime/stack.go

中的说明
  

按goroutine g-> stackguard设置为指向StackGuard字节   在堆栈底部上方。每个函数比较其堆栈   指向g-> stackguard的指针以检查是否溢出。砍一个   来自检查序列的指令,用于具有微小框架的功能,   允许堆栈向堆栈下方突出StackSmall字节   守护。大框架功能不会打扰检查和   总是调用morestack。序列为(对于amd64,其他序列为   相似):