Go 为什么没有 stackoverflows
I read in this presentation http://golang.org/doc/ExpressivenessOfGo.pdf page 42:
Safe
- no stack overflows
How is this possible? and/or how does Go works to avoid this?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
这是一个称为“分段堆栈”的功能:每个 goroutine 都有自己的堆栈,分配在堆上。
在最简单的情况下,编程语言实现在每个进程/地址空间使用一个堆栈,通常使用名为
push
和pop
(或类似的东西)的特殊处理器指令进行管理并实现作为从固定地址(通常是虚拟内存的顶部)开始的堆栈帧的动态数组。这(或曾经)很快,但并不是特别安全。当大量代码在同一地址空间(线程)中同时执行时,它会引起麻烦。现在每个人都需要自己的堆栈。但是,所有堆栈(也许除了一个堆栈)都必须是固定大小的,以免它们彼此重叠或与堆重叠。
然而,任何使用堆栈的编程语言都可以通过以不同的方式管理堆栈来实现:通过使用列表数据结构或类似的数据结构来保存堆栈帧,但实际上是在堆上分配的。在堆被填满之前不会发生堆栈溢出。
It's a feature called "segmented stacks": every goroutine has its own stack, allocated on the heap.
In the simplest case, programming language implementations use a single stack per process/address space, commonly managed with special processor instructions called
push
andpop
(or something like that) and implemented as a dynamic array of stack frames starting at a fixed address (commonly, the top of virtual memory).That is (or used to be) fast, but is not particularly safe. It causes trouble when lots of code is executing concurrently in the same address space (threads). Now each needs its own stack. But then, all the stacks (except perhaps one) must be fixed-size, lest they overlap with each other or with the heap.
Any programming language that uses a stack can, however, also be implemented by managing the stack in a different way: by using a list data structure or similar that holds the stack frames, but is actually allocated on the heap. There's no stack overflow until the heap is filled.
它使用分段堆栈。这基本上意味着它使用链表而不是固定大小的数组作为堆栈。当空间不足时,堆栈就会变大一点。
编辑:
这里有一些更多信息: http://golang.org/doc/go_faq.html#goroutines
这之所以如此伟大,并不是因为它永远不会溢出(这是一个很好的副作用),而是因为您可以创建内存占用非常小的线程,这意味着您可以拥有很多线程。
it uses a segmented stack. Which basically means it uses a linked list instead of a fixed size array as it's stack. When it runs out of space it makes the stack a little bigger.
edit:
Here is some more information: http://golang.org/doc/go_faq.html#goroutines
The reason this is so great is not because it'll never overflow (that's a nice side-effect), it's that you can create threads with a really small memory footprint, meaning you can have lots of them.
我不认为他们可以“完全”避免堆栈溢出。它们提供了一种方法来防止最典型的编程相关错误产生堆栈溢出。
当内存耗尽时,无法防止堆栈溢出。
I don't think they can "totally" avoid stack overflows. They provide a way to prevent the most typical programming-related errors to produce a stack overflow.
When the memory finishes there is no way to prevent a stack overflow.
即使 C 也可以做到这一点,但有一些基本上影响编译器的约束。
这是令人印象深刻的工程壮举,但不是语言设计的壮举。
Even C can do it with a few constraints that basically affect the compiler.
It is an impressive feat of engineering but not of language design.
我认为他们在这里指的是对数组的访问总是根据数组的实际长度进行检查,从而禁用 C 程序意外崩溃或恶意崩溃的最常见方式之一。
例如:
当它尝试更新数组中不存在的第 11 个元素时,会发生运行时错误
panic
。 C 会在堆上乱写乱画,并且可能也会以不受控制的方式崩溃。每个数组都知道它的长度。在某些情况下,如果编译器可以证明不需要检查,那么编译器还有空间优化检查。 (或者一个足够聪明的编译器也许可以静态地检测这个函数中的问题。)许多其他答案都在谈论堆栈的内存布局,但这实际上并不相关:您也可能遭受堆溢出攻击。
基本上,Go 的指针应该始终是类型安全的,无论是数组还是其他类型,除非您专门使用
unsafe
包。I think what they are referring to here is that access to arrays is always checked against the actual length of the array, thus disabling one of the most common ways by which C programs crash accidentally or are crashed maliciously.
For example:
will
panic
with a runtime error when it tries to update the non-existent 11th element of the array. C would scribble over the heap, and probably also crash but in an uncontrolled way. Every array knows its length. In some cases there will be scope for the compiler to optimize out the checks if it can prove they are not necessary. (Or a sufficiently smart compiler could perhaps statically detect a problem in this function.)Many of the other answers are talking about the memory layout of the stack but this is really not relevant: you can have heap overflow attacks too.
Basically Go's pointers should always be typesafe, with arrays and other types, unless you specifically use the
unsafe
package.