我在Microsoft Visual Studio Express 2012中编译了以下C程序:
int main() {
int a[300000];
return 0;
}
这会在msvcr110d.dll中发生堆栈溢出而崩溃!__ crtFlsGetValue()。
如果我将数组大小从300,000更改为200,000,它可以正常工作(因为这个简单的程序可以说是“工作”,因为它没有做任何事情)。
我在Windows 7上运行,并且还在Cygwin下使用gcc尝试了这个并且它产生了相同的行为(在这种情况下是一个seg错误)。
到底是什么?
答案 0 :(得分:5)
C中自动对象使用的空间大小存在特定于平台的限制(“堆栈大小”)。大于该大小的对象(在嵌入式平台上可能是几千字节,在台式机上可能是几兆字节)不能被声明为自动对象。反而使它们变为静态或动态。
同样,函数调用的深度也有限制,特别是在递归时。
检查编译器和/或平台文档,了解实际大小的详细信息,以及如何更改它的详细信息。 (例如,在Linux上查看ulimit
。)
答案 1 :(得分:2)
因为它被分配在堆栈上并且堆栈的大小有限,显然不足以容纳300000个整数。
使用堆分配la malloc
:
int* a = malloc(sizeof(int) * 300000);
// ...
free(a);
堆可以比堆栈容纳更多。
答案 2 :(得分:1)
本地变量声明堆栈中的空间。所以,如果你分配足够大的东西,堆栈将不可避免地溢出。
答案 3 :(得分:1)
线程堆栈的大小传统上受操作系统的限制,因为每个进程可用的虚拟地址空间量有限。
由于分配给线程堆栈的虚拟地址空间一旦分配就无法更改,除了为每个线程分配一个相当大但有限的块之外没有其他策略 - 即使大多数线程都会使用它很少。
类似地,对进程允许生成的线程数也有一个有限的限制。
猜测,这里的限制是1MB,然后Windows将线程数限制为 - 比如 - 256,这意味着32位进程可用的256MB 3GB虚拟地址空间被分配给线程堆栈 - 换句话说,1/12。
在64位系统上,显然有更多虚拟空间可供使用,但为了快速检测 - 并终止 - 无限递归,有一个限制仍然是明智的。