2

我正在尝试使用以下程序创建堆栈溢出运行时异常:

void f(int a) {
  cout << a << ", ";
  f(++a);
}

int main () {
  f(0);
  return 0;
}

当我运行这个程序时,我的计算机运行大约 261824call stack然后command terminated发生运行时错误。现在我想知道:

  1. 这是堆栈溢出的一个很好的例子吗?如果是,为什么command terminated会发生错误?
  2. 我怎么能trycatch堆栈溢出异常?
  3. 我有很多空闲内存;为什么我的堆栈没有使用我所有的内存?
  4. 我怎样才能确定堆栈的大小对应于我的call stack
4

2 回答 2

6

这些都是实现细节。从技术上讲,C++ 实现不需要堆栈,它只需要自动存储。至少有一个 C 实现使用堆中的链表(嗯,有点——据我了解,这是一个奇怪的系统)来进行自动存储。

但是,通常,堆栈是内存地址空间的一个连续区域,进程保留该区域仅用于存储自动变量和调用帧。它必须在发生其他任何事情之前保留,因为它必须是连续的,并且如果为其他目的分配了一些内存块,则堆栈将无法增长。

如果您想将整个内存地址空间用于堆栈,那么堆(又名空闲存储)将没有空间。所以堆栈不会使用所有内存......

1 MB 是设置堆栈的传统值:很少有程序真的需要更多,甚至适度避免将大量数据放在堆栈上。在多线程环境中,每个线程最终都有自己的堆栈:因此保持较小的堆栈也会使线程更便宜。现代系统可能会将其设置得更大,因为它们为每个进程提供了大量的地址空间。

在 64 位系统上,为堆栈使用 50 位地址空间相对容易(这比您的计算机当前可以处理的要多:谷歌数据中心处理 PB)。但是这样做的缺点是,在整个系统的虚拟内存被那个进程抢占之后,您只会在调试时破坏堆栈。这样做的好处并不是那么大。

堆栈的大小是实现定义的,而不是由 C++ 标准公开的。有关如何确定它的大小以及如何更改其大小的信息,请参阅您的编译器文档。

C++ 标准并没有规定当你破坏堆栈时会发生什么。一般来说,当堆栈被炸毁时,您可能会遇到严重的麻烦:编写代码使其不会发生,而不是在它发生后才抓住它。

于 2013-03-16T03:23:47.870 回答
4
  1. 是的,这是堆栈溢出。您收到的错误消息取决于平台——因此,如果您在不同类型的机器上运行它,您可能会看到“堆栈溢出”。
  2. 没有像这里看到的那样好的便携方式。这是因为您没有抛出异常,而是让操作系统以它想要的任何方式杀死您的进程。
  3. 您的堆栈限制远小于您的可用内存(堆栈通常为 8-20MB)。在特定的操作系统设置中,如果您确实需要更大的值,您可以重新配置此值(Solaris 上的 ulimit -s 100000 将其设置为 100MB)。但通常达到堆栈限制意味着你做错了什么。一个小的堆栈限制有助于操作系统使用虚拟内存分配方案,并且是堆栈溢出的早期错误捕获器(想象一个较慢的代码版本在一两个小时内消耗所有可用内存......对于其他运行的东西来说不是那么有趣)。
  4. 这可能取决于操作系统或编译器,并且不是 C++ 固有的东西。试试这个关于确定堆栈大小的各种方法的SO 链接。
于 2013-03-16T03:19:36.983 回答