2

我在 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 错误)。

有没有搞错?

4

4 回答 4

5

C 中自动对象使用的空间大小(“堆栈大小”)存在特定于平台的限制。大于该大小的对象(在嵌入式平台上可能是几千字节,在台式机上可能是几兆字节)不能声明为自动对象。将它们设为静态或动态。

同样,函数调用的深度也有限制,尤其是递归。

检查您的编译器和/或平台文档以获取有关实际大小以及如何更改它的详细信息。(例如在 Linux 上签出ulimit。)

于 2013-01-08T22:37:49.267 回答
3

因为它被分配在堆栈上并且堆栈的大小有限,显然不足以容纳 300000 个整数。

使用堆分配 a la malloc

int* a = malloc(sizeof(int) * 300000);
// ...
free(a);

堆可以容纳比堆栈更多的东西。

于 2013-01-08T22:38:10.670 回答
2

线程堆栈的大小传统上受到操作系统的限制,因为每个进程可用的虚拟地址空间量是有限的。

由于分配给线程堆栈的虚拟地址空间一旦分配就无法更改,因此除了为每个线程分配一个相当大但有限的块之外没有其他策略 - 即使大多数线程将使用它的很少.

同样,允许进程产生的线程数也有有限的限制。

猜测一下,这里的限制是 1MB,然后 Windows 将线程数限制为 - 比如说 - 256,这意味着 32 位进程可用的 3GB 虚拟地址空间中的 256MB 被分配给线程堆栈 - 或者把另一个方式,1/12。

在 64 位系统上,显然有更多的虚拟空间可供使用,但为了快速检测并终止无限递归,限制仍然是明智的。

于 2013-01-08T23:10:07.400 回答
1

局部变量从堆栈中声明空间。所以,如果你分配了足够大的东西,堆栈将不可避免地溢出。

于 2013-01-08T22:38:40.867 回答