如何创建无限递归,这将抛出堆栈溢出异常

How to create endless recursion which will throw stack overflow exception?

本文关键字:堆栈 异常 栈溢出 递归 何创建 创建 无限      更新时间:2023-10-16

我试图用以下程序创建堆栈溢出运行时异常:

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

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

    这是一个堆栈溢出的好例子吗?如果是,为什么会出现command terminated错误?
  1. 如何处理try, catch堆栈溢出异常?
  2. 我有很多空闲内存;为什么我的堆栈没有使用我所有的内存?
  3. 如何确定堆栈的大小对应于我的call stack ?

这些都是实现细节。从技术上讲,c++实现不需要堆栈,它只需要自动存储。至少有一种C实现在堆中使用链表(好吧,从我的理解来看,这是一个奇怪的系统)来实现它们的自动存储。

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

如果您想将整个内存地址空间用于堆栈,则没有空间用于堆(即自由存储)。所以堆栈不会使用所有的内存…

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

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

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

c++标准没有规定当你破坏堆栈时会发生什么。一般来说,当堆栈被破坏时,您可能会遇到严重的麻烦:编写代码以便它不会发生,而不是在它发生后捕获它。

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