我在这个演示中阅读到了第42页http://golang.org/doc/ExpressivenessOfGo.pdf:
安全
- 没有堆栈溢出
这是如何实现的?或者说,Go是如何避免这种情况发生的?
我在这个演示中阅读到了第42页http://golang.org/doc/ExpressivenessOfGo.pdf:
安全
- 没有堆栈溢出
这是如何实现的?或者说,Go是如何避免这种情况发生的?
push
和pop
(或类似名称)的特殊处理器指令进行管理,并作为从固定地址开始的堆栈帧的动态数组实现(通常是虚拟内存的顶部)。它使用分段栈。这基本上意味着它使用链表而不是固定大小的数组作为堆栈。当它用完空间时,会使堆栈变得更大一些。
编辑:
这里有更多信息:http://golang.org/doc/go_faq.html#goroutines
这样做之所以很好,不是因为它永远不会溢出(这是一个好的副作用),而是因为您可以创建具有非常小的内存占用的线程,这意味着您可以拥有很多线程。
我认为他们不能完全避免堆栈溢出。他们提供了一种防止最典型的与编程有关的错误导致堆栈溢出的方法。
当内存用尽时,就没有办法防止堆栈溢出。
即使是用C语言编写,也只需要满足一些基本影响编译器的限制。
这是一个令人印象深刻的工程成就,但并不是语言设计方面的。
我认为他们在这里所指的是,对数组的访问总是根据数组的实际长度进行检查,从而禁用了C程序意外崩溃或恶意崩溃的最常见方式之一。
例如:
package main
func main() {
var a [10]int
for i:= 0; i < 100; i++ {
a[i] = i
}
}
当尝试更新不存在的数组第11个元素时,panic
会引发运行时错误。C语言会在堆上涂写,并可能崩溃,但是无法控制。每个数组都知道它的长度。在某些情况下,如果编译器可以证明检查不必要,那么就有可能进行优化。(或者一个足够聪明的编译器可以在这个函数中静态地检测到问题。)
其他答案中许多人都在谈论堆栈的内存布局,但这实际上并不相关:您也可以遭受堆溢出攻击。
基本上,Go的指针应始终是类型安全的,包括数组和其他类型,除非您专门使用unsafe
包。