【问题标题】:Is there any limit on stack memory?堆栈内存有限制吗?
【发布时间】:2024-04-26 09:40:01
【问题描述】:

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

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

当全局声明相同的数组时,它工作得很好。(堆上的内存保存了它)。

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

我们有:

---堆栈---

-------

---堆----

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

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

【问题讨论】:

  • 这里有一点神话。您可能想查看this 的答案。

标签: c memory-management operating-system heap-memory stack-memory


【解决方案1】:

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

【讨论】:

  • 我正在使用 C/C++。编译器是 gcc.Windows 平台。此外,我在 linux 平台上也没有运行时错误。我可以轻松地在本地声明一个大小为 10^6 的数组。那么平台呢?
  • 我想创建一个 [400][3000] 大小的浮点二维数组 .... 在 linux 上使用 gcc 但由于内存不足无法!有什么建议吗????
【解决方案2】:

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

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

【讨论】:

  • 它是 C/C++。编译器-GCC。平台:Windows。也请阅读下面我的 cmets。
  • @Vikas:尽量不要通过“下面”来引用。 SO 上的帖子顺序不是一成不变的。
  • @Xavier:哦,我明白了。谢谢你的信息。 :)
【解决方案3】:

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

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

void main()
{
    main();
}

...导致堆栈溢出:

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

【讨论】:

  • 是的,肯定会给出运行时错误。但我的疑问是:如果本地数组声明(在堆栈上)导致运行时错误。为什么它在全球范围内逃脱。意味着我们的堆大小限制大于堆栈大小。可能是默认的!
  • 我得到的第一个错误是 返回类型不是 int 所以最好先摆脱非标准代码。
【解决方案4】:

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

【讨论】:

    【解决方案5】:

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

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

    【讨论】:

      【解决方案6】:

      与迄今为止的所有答案相反,在带有 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();
      }
      

      【讨论】: