【发布时间】:2011-05-12 17:38:44
【问题描述】:
【问题讨论】:
标签: memory-management stack language-design stack-overflow go
【问题讨论】:
标签: memory-management stack language-design stack-overflow go
这是一个称为“分段堆栈”的功能:每个 goroutine 都有自己的堆栈,allocated on the heap。
在最简单的情况下,编程语言实现对每个进程/地址空间使用一个堆栈,通常使用称为 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
}
}
panic 尝试更新数组中不存在的第 11 个元素时会出现运行时错误。 C 会在堆上乱涂乱画,并且可能还会崩溃,但以一种不受控制的方式。每个数组都知道它的长度。在某些情况下,如果编译器可以证明它们没有必要,编译器将有优化检查的空间。 (或者一个足够聪明的编译器可能会静态检测到这个函数中的问题。)
许多其他答案都在谈论堆栈的内存布局,但这实际上并不相关:您也可以进行堆溢出攻击。
基本上,Go 的指针应该始终是类型安全的,包括数组和其他类型,除非您专门使用 unsafe 包。
【讨论】: