在Linux中,进程的堆栈大小是否有限制?这与机器的RAM有关吗?
我想知道这个问题是为了限制递归调用函数的深度。
在Linux中,进程的堆栈大小是否有限制?这与机器的RAM有关吗?
我想知道这个问题是为了限制递归调用函数的深度。
堆栈通常受资源限制的影响。您可以使用 ulimit -a
命令查看安装的默认设置:
stack size (kbytes, -s) 8192
(这表明我的是8MB,非常大)。
如果您删除或增加该限制,仍然无法在堆栈中使用机器中的所有RAM-堆栈从进程地址空间顶部附近的一点向下增长,并且在某个时候它将遇到您的代码、堆或已加载库。
i386
的 ABI,这是不正确的。在其中,堆栈位于其他所有内容下面,理论上可以增长到略高于 128MiB
。在 AMD64
ABI 中,它从 128GiB
标记下方增长,略低于共享库。因此,它理论上可以覆盖代码/数据,但仅限于主程序或其堆。 - ivan_pozdeev/proc/<pid>/maps
。例如,参见此提交消息,描述了2004年实施的新布局 - 旧布局和新布局都将堆栈放在最后。 - caf这在很大程度上取决于您使用的架构(32位或64位)以及是否支持多线程。
默认情况下,在单线程进程中,也就是由操作系统在exec()时创建的主线程中,堆栈通常会增长,直到它触碰到地址空间中的其他东西。这意味着在32位机器上,通常可以有1G的堆栈大小。
但是,在多线程32位进程中,情况绝对不是这样的。在多线程进程中,堆栈共享地址空间,因此需要进行分配,因此它们通常被给予一小部分地址空间(例如1M),以便可以创建许多线程而无需耗尽地址空间。
因此,在多线程进程中,堆栈相对较小且有限,在单线程进程中,堆栈基本上可以增长至触碰地址空间中的其他部分(默认分配机制试图确保不会太快发生)。
在64位机器上,当然有更多的地址空间可供使用。
无论如何,您始终可能会用尽虚拟内存,在这种情况下,您将收到SIGBUS或SIGSEGV等信号。
我原本想评论已接受的答案,但显然我的声望不够....
真正的堆栈溢出有时可能很微妙,并且不会引起任何错误消息或警告。我曾经遇到这样一种情况,唯一的症状是套接字连接会失败,并显示奇怪的SSL错误。其他一切都正常工作,线程可以malloc()、抓取锁、与数据库通信等等。但新的连接在SSL层面上会失败。
由于来自GnuTLS内部的堆栈跟踪,我对真正的原因感到困惑。在花费大量时间尝试弄清楚之后,几乎向他们的团队报告了这些跟踪信息。
最终发现,堆栈大小被设置为8Mb,一旦将其提高,问题就消失了。将堆栈降低回8Mb会带回问题(ABA)。
因此,如果您正在排除似乎没有其他警告或未初始化内存错误的奇怪套接字错误,那么可能是堆栈溢出。
alloca
或C99 VLA可以跳过守卫页,进入另一个区域。(如果恶意地对一个在使用本地数组之前不检查大小的程序进行此操作,则会发生堆栈冲突攻击。有关更多编译器选项以加强防护的信息,请参见Linux进程堆栈被本地变量(堆栈保护)溢出,例如通过堆栈探针确保在增加超过一页的堆栈时触摸中间页面,即使在不需要的Linux上也是如此。) - Peter Cordes