我已经知道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)
,而第二个不包含。
我想这是一个优化,但是为什么呢?
答案 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,其他序列为 相似):