2010-04-17 390 views
10

Linux中的进程的大小stack是否有限制?它是否仅仅依赖于机器的RAM? 我想知道这是为了限制递归调用函数的深度。Linux中进程的堆栈大小是否有限制

谢谢。

+0

你总是可以一起快速测试,看看堆栈有多深。 CountDepth(int d){CountDepth(d + 1); } – Martin 2010-04-17 00:21:58

+2

@Martin:虽然当你真的在函数中做某些事情时,“深度”会降低,而变量。 – GManNickG 2010-04-17 00:25:06

+0

这是真的,但这是一个很好的估计。如果你真的想要的话,你可以计算临时变量和方法参数中使用的位数,并准确地为给定函数计算 – Martin 2010-04-17 02:55:13

回答

22

堆栈通常受限于资源限制。您可以看到默认的设置是使用ulimit -a安装什么:

stack size    (kbytes, -s) 8192 

(这表明我的是8MB,这是巨大的)。

如果您删除或增加了该限制,您仍然无法使用机器中的所有RAM用于堆栈 - 堆栈从进程地址空间顶部附近的点向下增长,并且在某些指向它将运行到您的代码,堆或加载库。

+1

“在某些时候它会运行到你的代码,堆或加载库”我怀疑这是否会成为64位系统上的问题,如Linux x86_64? – 2015-02-06 01:51:04

+0

@SamWatkins:好的 - 这个答案是5年前写的,并且是在32位环境中。 – caf 2015-02-06 11:24:20

+0

如果[ABI](http://www.sco.com/developers/devspecs/abi386-4.pdf)是可信的,则这对'i386'不正确。其中,堆栈位于其他所有内容之下,理论上可以增长到超过128MiB。在['AMD64' ABI](https://www.uclibc.org/docs/psABI-x86_64.pdf)中,它在'128GiB'标记下增长,就在共享库下。所以它理论上可以覆盖代码/数据,但只能覆盖主程序或堆。 – 2016-09-25 21:06:49

5

该限制可以由管理员设置。

请参阅man ulimit

有可能是你不能跨越的默认值。如果你不得不担心堆栈限制,我会说你需要重新考虑你的设计,也许写一个迭代版本?

+1

或者只是编写一个使用手动管理堆栈而不是函数调用堆栈的递归版本。 – 2010-04-17 00:59:29

+2

@Roger Pate:这基本上是迭代版本。 – slebetman 2013-04-29 01:59:23

3

它很大程度上取决于您所在的体系结构(32位或64位)以及您是否是多线程的。

默认情况下,在单线程进程中,即在exec()时由操作系统创建的主线程,堆栈通常会增长,直到在地址空间中遇到其他东西。这意味着在32位机器上通常可以拥有1G的堆栈。

但是,在多线程32位进程中绝对不是这种情况。在多线程处理中,堆栈共享地址空间,因此需要分配地址空间,因此它们通常会获得少量地址空间(例如1M),因此可以在不耗尽地址空间的情况下创建多个线程。

因此,在一个多线程的进程中,它是小而有限的,在一个单线程的进程中,基本上直到你在地址空间(默认的分配机制试图确保不会太快发生)碰到别的东西。

在64位机器中,当然还有更多的地址空间可供使用。

在任何情况下,您总是可以用完虚拟内存,在这种情况下,您将获得SIGBUS或SIGSEGV或其他东西。

0

本来评论公认的答案,但显然我需要更多的代表....

真正的堆栈溢出可能是微妙的,并不总是引起任何错误消息或警告。我只是有一种情况,唯一的症状是套接字连接会失败,出现奇怪的SSL错误。其他一切正常。线程可以malloc(),抢锁,与数据库交谈等。但是新连接在SSL层失败。

由于GnuTLS中的堆栈轨迹很好,所以我对这个真正的原因感到非常困惑。在花费大量时间试图弄清楚之后,几乎将这些痕迹报告给了他们的团队。

最终发现stacksize被设置为8Mb,并立即提升后问题消失。将堆叠降回8Mb带来了问题(ABA)。

所以,如果你正在排除什么似乎是奇怪的套接字错误,没有任何其他警告或未初始化的内存错误....它可能是堆栈溢出。

+1

不应该堆栈后面有未映射/不可写的块(上面和下面),以防止这种大屠杀?如果我是正确的,堆栈如何溢出不会导致SEGV或类似故障?我建议你的错误的原因可能是别的,堆栈变化通过巧合(准heisenbug)来修正它。 – 2015-02-06 01:52:16