【问题标题】:What does "ulimit -s unlimited" do?“ulimit -s 无限”有什么作用?
【发布时间】:2013-01-06 10:49:44
【问题描述】:

堆栈分配有很多相关的问题是可以理解的

What and where are the stack and heap?

Why is there a limit on the stack size?

Size of stack and heap memory

但是在各种 *nix 机器上我可以发出 bash 命令

ulimit -s unlimited

或 csh 命令

set stacksize unlimited

这如何改变程序的执行方式?对程序或系统性能是否有任何影响(例如,为什么这不是默认设置)?

如果涉及更多系统细节,我主要关心的是在 x86_64 硬件上运行的 Linux 上使用 GCC 编译的程序。

【问题讨论】:

    标签: linux stack ulimit


    【解决方案1】:

    当您调用函数时,会在堆栈上分配一个新的“命名空间”。这就是函数可以具有局部变量的方式。随着函数调用函数,函数又调用函数,我们不断在堆栈上分配越来越多的空间来维护这种深层的命名空间层次结构。

    为了限制使用大量堆栈空间的程序,通常通过ulimit -s 设置限制。如果我们通过ulimit -s unlimited 取消该限制,我们的程序将能够继续为不断增长的堆栈占用 RAM,直到最终系统完全耗尽内存。

    int eat_stack_space(void) { return eat_stack_space(); }
    // If we compile this with no optimization and run it, our computer could crash.
    

    通常,使用大量堆栈空间是偶然的,或者是非常深的递归的症状,可能不应该过多地依赖堆栈。因此堆栈限制。

    对性能的影响很小,但确实存在。使用time 命令,我发现消除堆栈限制将性能提高了几分之一秒(至少在 64 位 Ubuntu 上)。

    【讨论】:

    • with gcc-4.7 -O3 你的 smash_the_stack 例子是尾递归的被翻译成一个无限循环,没有任何调用。
    • @BasileStarynkevitch 该死的。我认为这一点已经说得很清楚了。如果您希望 gcc 不优化堆栈粉碎以用于教育过期,只需使用 gcc -O0 编译它。
    • @Maxwell 两个错误:堆栈大小限制与防止“整个系统”崩溃无关。 RAM 就是 RAM,内核的工作是决定如何将其映射为堆栈或堆。制作 100GB 的堆栈并不比在堆上分配 100GB 更有害:操作要么失败(sbrk 或 exec 失败),要么会出现过量使用,并且在您使用内存时进程将被终止,直到系统能够兑现它再次记忆承诺。无论哪种情况,整个系统的完整性都是安全的。进程无法击败内核。
    • @Maxwell 其次,超过堆栈大小与堆栈粉碎是完全不同的问题。当发生堆栈溢出时,内核会终止该进程,仅此而已。没有任何不应该写入堆栈的内容,并且不会造成任何损害(除了进程终止)。
    • 这个答案是完全错误的。 Linux 上的每个进程都有自己的堆栈——没有系统堆栈空间之类的东西。堆栈在 x86 上向下增长,当堆栈顶部(实际上是堆栈内存的底部)达到预设限制或遇到另一个内存映射时会发生溢出。堆栈缓冲区溢出发生在相反的方向。如果堆栈向上增长,则很难覆盖返回地址。
    【解决方案2】:

    堆栈大小可以确实是无限的。 _STK_LIM默认值_STK_LIM_MAX 是每个架构都不同的东西,从 include/asm-generic/resource.h 可以看出:

    /*
     * RLIMIT_STACK default maximum - some architectures override it:
     */
    #ifndef _STK_LIM_MAX
    # define _STK_LIM_MAX           RLIM_INFINITY
    #endif
    

    从这个例子中可以看出,泛型值是无限的,其中RLIM_INFINITY 在泛型情况下再次定义为:

    /*
     * SuS says limits have to be unsigned.
     * Which makes a ton more sense anyway.
     *
     * Some architectures override this (for compatibility reasons):
     */
    #ifndef RLIM_INFINITY
    # define RLIM_INFINITY          (~0UL)
    #endif
    

    所以我想真正的答案是 - 堆栈大小可能会受到某些架构的限制,那么无限的堆栈跟踪将意味着 _STK_LIM_MAX 定义的任何内容,如果它是无限的 - 它是无限的。有关将其设置为无限的含义以及它可能产生的影响的详细信息,请参阅另一个答案,它比我的要好。

    【讨论】:

    • 这似乎不是真的。在我的系统上,linux/resource.h 中的值是 10*1024*1024。这也是“ulimit -s”打印的值。我用 20 MB 的静态数组编译了一个测试程序,它出现了段错误。但是,如果我发出命令“ulimit -s unlimited”,它不会崩溃。
    • 嗯,这很有趣。我的印象是它不会超过这个限制。
    • @BrianHawkins:过失,做了更多的研究,调整了答案。如果此信息无关紧要,我可以一起删除整个答案。
    【解决方案3】:

    ulimit -s unlimited 让堆栈无限增长。

    如果您通过递归编写程序,这可能会防止您的程序崩溃,特别是如果您的程序不是尾递归(编译器可以“优化”那些),并且递归深度很大。

    【讨论】:

    • 为什么不将“无限”设为默认堆栈大小?我的用例不涉及递归,而是包含超过大多数系统默认值的大型静态数组的旧 Fortran 程序。
    • 因为一个完全错误的程序可能会使您的系统崩溃。仅当您相信程序不会吃掉所有可用内存时,才必须使用此选项
    • 一个有缺陷的程序也可以继续从堆(malloc)分配并崩溃/冻结系统。系统通常不会设置堆限制。
    猜你喜欢
    • 2019-07-30
    • 2016-09-10
    • 2011-09-20
    • 1970-01-01
    • 1970-01-01
    • 2015-12-31
    • 1970-01-01
    • 2013-08-05
    • 2020-10-04
    相关资源
    最近更新 更多