在 Go 中,每个 goroutine 都有一个固定大小的栈空间,用于存储局部变量、函数调用信息等。栈空间的大小默认为 2KB,但可以使用 runtime.GOMAXPROCS 函数设置。
当 goroutine 需要的栈空间超过当前大小时,会触发栈空间的扩容。扩容时,Go 会在堆空间分配一个新的栈空间,并将旧的栈空间中的数据复制到新的栈空间中,然后将当前栈指针指向新的栈空间。栈空间的大小会以指数级别增长,以减少扩容的次数。
当 goroutine 的栈空间有很多闲置空间时,会触发栈空间的缩容。缩容时,Go 会将当前栈空间中未使用的空间释放回堆空间。
下面是一个简单的示例,展示了栈空间的扩容和缩容过程:
package main
import (
"fmt"
"runtime"
)
func main() {
var a [1024 * 1024]byte
fmt.Println("stack:", &a[0], len(a))
go func() {
var b [4 * 1024 * 1024]byte
fmt.Println("stack:", &b[0], len(b))
}()
for i := 0; i < 10; i++ {
runtime.Gosched()
}
}
在该示例中,我们定义了一个大小为 1MB 的数组 a,并打印出其地址和长度。然后启动一个新的 goroutine,在其中定义一个大小为 4MB 的数组 b,并打印出其地址和长度。最后,我们使用 runtime.Gosched() 函数让当前 goroutine 让出 CPU 执行时间,给其他 goroutine 执行的机会。我们循环执行 runtime.Gosched() 函数 10 次,以保证新的 goroutine 有足够的时间执行。
运行该示例,我们可以看到输出如下:
stack: 0xc000016090 1048576
stack: 0xc00004a090 4194304
可以看到,数组 a 所在的栈空间大小为 1MB,数组 b 所在的栈空间大小为 4MB。这表明,在 Go 中,不同的 goroutine 可以拥有不同大小的栈空间。另外,在输出中,我们还可以看到两个数组所在的地址不同,这表明它们分别位于不同的栈空间中。