为了账号安全,请及时绑定邮箱和手机立即绑定

为什么堆栈溢出取决于Go中如何访问数组?

为什么堆栈溢出取决于Go中如何访问数组?

Go
慕标5832272 2021-12-13 10:37:55
考虑以下 Go 程序:package mainfunc main() {    var buffer [100000000]float64    var i int    for i = range buffer {        buffer[i] = float64(i)    }}使用“go run test1.go”,它可以工作。(除非您的 RAM 太少。)现在,我简单地扩展这个程序:package mainfunc main() {    var buffer [100000000]float64    var i int    var value float64    for i, value = range buffer {        value = value        buffer[i] = float64(i)    }}“go run test2.go”产生:runtime: goroutine stack exceeds 1000000000-byte limitfatal error: stack overflowruntime stack:runtime.throw(0x473350, 0xe)        /usr/local/go/src/runtime/panic.go:527 +0x90runtime.newstack()        /usr/local/go/src/runtime/stack1.go:794 +0xb17runtime.morestack()        /usr/local/go/src/runtime/asm_amd64.s:330 +0x7fgoroutine 1 [stack growth]:main.main()        /home/bronger/src/go-test/test3.go:3 fp=0xc860075e50 sp=0xc860075e48runtime.main()        /usr/local/go/src/runtime/proc.go:111 +0x2b0 fp=0xc860075ea0 sp=0xc860075e50runtime.goexit()        /usr/local/go/src/runtime/asm_amd64.s:1696 +0x1 fp=0xc860075ea8 sp=0xc860075ea0exit status 2在我看来,在 test1.go 中,使用了堆,而在 test2.go 中,使用了堆栈。为什么?
查看完整描述

1 回答

?
摇曳的蔷薇

TA贡献1793条经验 获得超6个赞

根据Go 规范:


范围表达式在循环开始前计算一次,但有一个例外:如果范围表达式是数组或指向数组的指针,并且至多存在一个迭代变量,则仅计算范围表达式的长度


因此,在第一个程序中,仅评估缓冲区的长度并将其放置在堆栈中。


在第二个程序中,整个缓冲区在迭代之前被放置在堆栈上。因为在编译期间缓冲区的大小是已知的,所以 Go 编译器将指令放在函数的开头以预先分配堆栈空间。这就是为什么恐慌跟踪指向函数的开头。


在这两种情况下buffer都是在堆上分配的。这可以通过以下方式确认


$ go build -gcflags=-m

./main.go:4: moved to heap: buffer

请注意,如果您创建buffer一个全局变量,程序的行为将类似。


但是,如果您更改buffer为切片 ( buffer := make([]float64, 100000000)),则程序在两种情况下都会成功。发生这种情况是因为切片只是一个指向实际数组的指针,并且它只占用堆栈上的几个字节,而与支持数组的大小无关。所以修复你的第二个程序的最简单的方法是让它迭代切片而不是数组:


....

for i, value = range buffer[:] {

    ....

}

令人惊讶的是,如果您尝试创建更大的数组,[1000000000]float64那么编译器会抱怨(堆栈帧太大(> 2GB))。我认为它在编译第二个程序时也应该抱怨,而不是让它恐慌。您可能想将此问题报告给http://github.com/golang/go/issues


查看完整回答
反对 回复 2021-12-13
  • 1 回答
  • 0 关注
  • 261 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号