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
- 1 回答
- 0 关注
- 261 浏览
添加回答
举报