英文:
How come Go doesn't have stackoverflows
问题
我在这个演示文稿中阅读到 http://golang.org/doc/ExpressivenessOfGo.pdf 的第42页:
>安全
>
>- 没有堆栈溢出
这是如何实现的?Go语言是如何避免这种情况的?
英文:
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?
答案1
得分: 16
这是一个名为“分段栈”的特性:每个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
and pop
(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.
答案2
得分: 5
它使用分段栈。这基本上意味着它使用链表而不是固定大小的数组作为它的栈。当它的空间用完时,它会使栈稍微变大。
编辑:
这里有更多信息: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.
答案3
得分: 2
我不认为他们能够完全避免堆栈溢出。他们提供了一种方式来防止最典型的与编程相关的错误导致堆栈溢出。
当内存用尽时,无法防止堆栈溢出。
英文:
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.
答案4
得分: 0
即使是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.
答案5
得分: 0
我认为他们在这里所指的是,对数组的访问总是根据数组的实际长度进行检查,从而禁用了C程序意外崩溃或恶意崩溃的最常见方式之一。
例如:
package main
func main() {
var a [10]int
for i:= 0; i < 100; i++ {
a[i] = i
}
}
当它尝试更新数组中不存在的第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:
package main
func main() {
var a [10]int
for i:= 0; i < 100; i++ {
a[i] = i
}
}
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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论