C / C ++程序的最大堆栈大小


115

我想在100 X 100的阵列上做DFS。(数组的表示元素代表图形节点)因此,假设情况最糟,递归函数调用的深度可能会达到10000,而每次调用最多会占用20个字节。那么可行的方法是否有可能发生堆栈溢出?

C / C ++中的最大堆栈大小是多少?

请同时为以下两者指定gcc:
1)Windows上的cygwin
2)Unix

一般限制是什么?


11
您知道您可以实现深度优先搜索而无需递归,对吗?
塞巴斯蒂安

4
不,我不知道,请解释。
2009年

1
我在回答中做了一个没有递归的DFS的小例子
Andreas Brinck

56
再加上一个有关实际堆栈溢出的问题
Sam Watkins 2015年

3
@SamWatkins是的,名称Stack Overflow对我来说最大的问题之一是,我可能会在Google上查找“ stack stackover”并最终进入该网站,但不一定/不太可能出现有关堆栈溢出的问题...
lalilulelost 18-3-20

Answers:


106

我认为在Visual Studio中,默认堆栈大小为1 MB,因此,如果递归深度为10,000,则每个堆栈帧最多可以包含约100个字节,这对于DFS算法应该足够了。

包括Visual Studio在内的大多数编译器都允许您指定堆栈大小。在某些(全部)Linux操作系统上,堆栈大小不是可执行文件的一部分,而是操作系统中的环境变量。然后,您可以使用来检查堆栈大小,ulimit -s然后使用来将其设置为新值ulimit -s 16384

这是gcc默认堆栈大小的链接

没有递归的DFS:

std::stack<Node> dfs;
dfs.push(start);
do {
    Node top = dfs.top();
    if (top is what we are looking for) {
       break;
    }
    dfs.pop();
    for (outgoing nodes from top) {
        dfs.push(outgoing node);
    }
} while (!dfs.empty())

12
仅供参考,BFS相同,除了使用FIFO而不是堆栈。
史蒂夫·杰索普

是的,或者在STL语言中使用带有pop_front / push_back的std :: deque
Andreas Brinck

具有堆栈结果的DFS将与递归版本不同。在某些情况下,这并不重要,但在其他情况下(例如,以拓扑形式),您将得到错误的结果
spin_eight

是的,VS的默认限制确实为1MB。可以在Microsoft文档中找到更多信息以及设置其他值的方法:msdn.microsoft.com/zh-cn/library/tdkhxaks
v=vs.140).aspx

我更喜欢为此类算法使用显式堆栈数据结构,而不是递归,这样1.不依赖于系统堆栈的大小,2.可以将算法更改为使用其他数据结构,例如队列或优先级队列而不会抛出删除所有代码。
山姆·沃特金斯

47

线程堆栈通常较小。您可以在链接时更改默认值,也可以在运行时更改。作为参考,一些默认值为:

  • glibc i386,x86_64 7.4 MB
  • Tru64 5.1 5.2 MB
  • Cygwin 1.8 MB
  • Solaris 7..10 1 MB
  • MacOS X 10.5 460 KB
  • AIX 5 98 KB
  • OpenBSD 4.0 64 KB
  • HP-UX 11 16 KB

14
由Bruno Haible 凭经验
pixelbeat

17

平台相关,工具链相关,ulimit相关,参数相关....完全没有指定,并且有许多静态和动态属性可以影响它。


4
没有“一般限制”。在Windows上,具有默认的VC ++链接器选项和默认的CreateThread行为,通常每个线程大约1 MiB。在具有无限用户的Linux上,我相信通常没有限制(堆栈可以向下扩展以占据几乎整个地址空间)。基本上,如果您必须询问,则不应该使用堆栈。
DrPizza

1
在嵌入式系统上,您的容量可能不超过4k。在这种情况下,您甚至必须询问使用堆栈的合理时间。答案通常是高卢耸耸肩。
史蒂夫·杰索普

1
是的,内核模式也经常出现这种情况。
DrPizza

6

是的,有可能出现堆栈溢出。C和C ++标准不规定诸如堆栈深度之类的东西,这些通常是环境问题。

大多数像样的开发环境和/或操作系统都可以让您在链接或加载时定制进程的堆栈大小。

您应该指定要使用的操作系统和开发环境,以获得更有针对性的帮助。

例如,在Ubuntu Karmic Koala下,gcc的默认设置为保留2M,并提交4K,但是在链接程序时可以更改。使用--stack选项ld来做到这一点。


2
@lex:没有一般限制。这取决于很多参数。
Michael Foukarakis,2009年

@paxdiablo:WHat是保留和提交的意思吗?
2009年

2
保留是要分配多少地址空间,承诺是要附加备份存储空间的地址。换句话说,保留地址空间并不意味着内存将在需要时存在。如果您从未使用超过4K的堆栈,则不会浪费其他1.6M的实际内存。如果您想保证会有足够的堆栈,则保留和提交应相同。
paxdiablo

2
@paxdiablo 2M-4k不是160万。只是说。(让我在阅读您的评论的前3次感到困惑)
griffin

2
@griffin,在3年以上时间内第一个意识到这一点的人感到很荣幸。我当然意思是“剩下的”-我会避免使用实际数字,以免犯下另一个可能的错误:-)
paxdiablo 2013年

5

我只是在工作中用光了堆栈,它是一个数据库,并且正在运行一些线程,基本上以前的开发人员在堆栈上抛出了一个大数组,而且堆栈还是很低。该软件是使用Microsoft Visual Studio 2015编译的。

即使线程用完了堆栈,它也默默地失败并继续运行,但只有在访问堆栈中的数据内容时,它才会堆栈溢出。

我能提供的最佳建议是不要在堆栈上声明数组-尤其是在复杂的应用程序和线程中,而要使用堆。那就是它的目的;)

另外请记住,声明堆栈时它可能不会立即失败,而只会在访问时失败。我的猜测是,编译器“乐观地”在Windows下声明了堆栈,即它将假定已经声明了堆栈并且大小足够大,直到可以使用它为止,然后才发现堆栈不存在。

不同的操作系统可能具有不同的堆栈声明策略。如果您知道这些政策是什么,请发表评论。


3

我不确定在矩形阵列上进行深度优先搜索的意思,但是我假设您知道自己在做什么。

如果堆栈限制是一个问题,您应该能够将递归解决方案转换为迭代解决方案,该解决方案将中间值压入从堆分配的堆栈中。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.