11

我正在经历其中一个线程。一个程序崩溃了,因为它在函数内本地声明了一个 10^6 的数组。

给出的原因是堆栈上的内存分配失败导致崩溃。

当全局声明相同的数组时,它运行良好。(堆上的内存保存了它)。

现在,让我们假设,堆栈向下增长并向上堆。

我们有:

- -堆 - -

------------------

- -堆 - -

现在,我相信如果在堆栈上分配失败,它也必须在堆上失败。

所以我的问题是:堆栈大小有限制吗?(越界导致程序崩溃)。还是我错过了什么?

4

6 回答 6

7

是的,堆栈总是有限的。在多种语言/编译器中,您可以设置请求的大小。

当前语言的默认值(如果未手动设置)通常约为1MB,这已经足够,除非您执行通常不推荐的操作(例如在堆栈上分配巨大的数组)

于 2010-05-06T10:18:36.153 回答
5

这一切都取决于您使用的语言和编译器。但是用例如 C 或 C++ 编译的程序在程序启动时分配一个固定大小的堆栈。堆栈的大小通常可以在编译时指定(在我的特定编译器上,它默认为 1 MB)。

于 2010-05-06T09:56:17.913 回答
5

与到目前为止的所有答案相反,在带有 GCC 的 Linux 上(我想所有现代 POSIX 操作系统都是如此),最大堆栈大小是操作系统强制执行的安全限制,可以轻松解除。

我制作了一个小程序,它递归调用一个函数,直到在堆栈上分配至少 10 GB,等待终端上的输入,然后安全地从所有递归调用返回到main.

#include <stdio.h>
#include <string.h>
#include <sys/time.h>
#include <sys/resource.h>

void grow(unsigned cur_size)
{
    if(cur_size * sizeof(int) < 10ul*1024ul*1024ul*1024ul) {
        unsigned v[1000];
        v[0] = cur_size;
        for(unsigned i = 1; i < 1000; ++i) {
            v[i] = v[i-1] + 1;
        }

        grow(cur_size + 1000);

        for(unsigned i = 0; i < 1000; ++i) {
            if(v[i] != cur_size + i)
                puts("Error!");
        }
    } else {
        putchar('#');
        getchar();
    }
}

int main()
{
    struct rlimit l;
    l.rlim_max = RLIM_INFINITY;
    l.rlim_cur = RLIM_INFINITY;
    setrlimit(RLIMIT_STACK, &l);

    grow(0);
    putchar('#');
    getchar();
}
于 2016-03-15T22:26:26.583 回答
2

您没有提到哪种编程语言,但在 Delphi 中,编译选项包括最大和最小堆栈大小,我相信所有编译语言都会存在类似的参数。

我当然不得不偶尔增加自己的最大值。

于 2010-05-06T09:58:49.903 回答
1

是的,大多数语言的堆栈大小都有限制。例如,在 C/C++ 中,如果您有一个不正确编写的递归函数(例如不正确的基本情况),您将溢出堆栈。这是因为,忽略尾递归,对函数的每次调用都会创建一个新的堆栈帧,该堆栈帧会占用堆栈空间。做到这一点,你会用完空间。

在 Windows (VS2008) 上运行这个 C 程序...

void main()
{
    main();
}

...导致堆栈溢出:

Unhandled exception at 0x004113a9 in Stack.exe: 0xC00000FD: Stack overflow.

于 2010-05-06T10:03:20.167 回答
1

也许不是一个很好的答案,但可以让您更深入地了解 Windows 通常如何管理内存:Pushing the Limits of Windows

于 2010-05-06T10:06:49.203 回答