在使用GNU编译器在Linux上编译C++应用程序时如何改变堆栈大小

67

在OSX上,使用g++编译C++程序时,我使用

LD_FLAGS= -Wl,-stack_size,0x100000000

但在SUSE Linux中,我经常会遇到以下错误:

x86_64-suse-linux/bin/ld: unrecognized option '--stack'

以及类似的功能。

我知道可以使用

ulimit -s unlimited

但这种方式并不好,因为并非每个用户都能这样做。

我如何在Linux中使用GCC为单个应用程序增加堆栈大小?


2.6.18.8-0.9-default #1 SMP Sun Feb 10 22:48:05 UTC 2008 x86_64 x86_64 x86_64 GNU/Linux - asdf
gcc --ver:gcc版本4.1.2 20061115(预发布版)(SUSE Linux) - asdf
尝试在Stack Clash修复之后设置rlimit_stack可能会导致失败或相关问题。还请参阅Red Hat Issue 1463241 - jww
ld -v,请。 - Sergei Krivonos
5个回答

81

你可以使用setrlimit函数来在程序中设置堆栈大小,例如:

#include <sys/resource.h>

int main (int argc, char **argv)
{
    const rlim_t kStackSize = 16 * 1024 * 1024;   // min stack size = 16 MB
    struct rlimit rl;
    int result;

    result = getrlimit(RLIMIT_STACK, &rl);
    if (result == 0)
    {
        if (rl.rlim_cur < kStackSize)
        {
            rl.rlim_cur = kStackSize;
            result = setrlimit(RLIMIT_STACK, &rl);
            if (result != 0)
            {
                fprintf(stderr, "setrlimit returned result = %d\n", result);
            }
        }
    }

    // ...

    return 0;
}

注意:即使使用此方法增加堆栈大小,也不应在main()函数本身中声明大的局部变量,因为在进入main()函数之前,getrlimit/setrlimit代码有机会更改堆栈大小之前,您可能会遇到堆栈溢出。因此,任何大型局部变量应仅定义在随后从main()调用的函数中,在成功增加堆栈大小之后。


我在 SLES 11 上尝试了它。即使值已设置,我也无法根据新限制定义局部变量 ->“段错误”。只有当我在命令行中运行“ulimit -s 16000”时,我才能定义一个类似“char x [14000000]”的局部变量。显然,此代码未设置堆栈大小。有任何想法吗? - Peter VARGA
1
@AlBundy:我能告诉你的是,上面的代码在我的OS X和各种Linux版本上都可以工作。但是我有一个想法:你是否尝试在main()函数中声明一个大的局部变量?这当然行不通,因为在你甚至到达getrlimit/setrlimit代码之前,就会出现堆栈溢出。将大的局部变量放在另一个函数中,然后从main中调用此函数(在getrlimit/setrlimit代码之后)。 - Paul R
1
@PaulR:好的。我在main()中尝试了一下,但是在我设置新限制之后才进行的。显然这样行不通。当我从main()调用一个有巨大本地变量的函数时,它就可以工作了。我现在使用不同的限制进行了检查,所有都完美地工作了。结论:堆栈限制必须在main()中设置,以便在程序的其余部分中生效。我还必须关闭ssh会话,因为我正在玩ulimit -s,并且我总是得到-1作为返回代码。 - Peter VARGA
谢谢确认 - 我现在已经在答案中添加了一条注释,以防其他人遇到相同的问题。 - Paul R
@AlBundy:每个线程仍将获得线程的默认堆栈大小(当然,您可以轻松更改此大小),但通过增加进程堆栈大小,您将能够创建更多线程,如果这是您的意思。 - Paul R
显示剩余4条评论

24

不要使用 stack_size,而是使用如下方式的 --stack

gcc -Wl,--stack,4194304 -o program program.c

这个示例应该会给你 4MB 的堆栈空间。在MinGW的GCC上工作正常,但正如manpage所说,“此选项专为链接器针对i386 PE目标端口而设计”(即仅适用于输出Windows二进制文件)。看起来对于ELF二进制文件没有类似的选项。


3
不幸的是,我尝试了这个方法,但它没有成功:/usr/lib64/gcc/x86_64-suse-linux/4.1.2/../../../../x86_64-suse-linux/bin/ld: 无法识别选项 '--stack' /usr/lib64/gcc/x86_64-suse-linux/4.1.2/../../../../x86_64-suse-linux/bin/ld: 使用 --help 选项获取用法信息 collect2: ld 返回了 1 个退出状态 - asdf
是的,我编辑了我的答案,因为我注意到它不适用于ELF输出。很抱歉我在这方面帮不上忙。 - AndiDog
3
好的,你救了我。我用的是Windows ;)。谢谢! - Jan Święcki
在CMake中,有一些命令可以设置此选项,在Windows上所有这些命令都对我有效。 - Gumby The Green

13

这是一个古老的话题,但这里列出的所有标志都对我没有用。无论如何,我发现-Wl,-z,stack-size=4194304(例如4MB)似乎有效。


7

3
-fsplit-stack 对我的使用情况造成了约20%的性能下降。 - Dennis
2
嗨,@Dennis,请考虑将此性能与堆的使用进行比较。 - Sergei Krivonos

2

就像我说的那样,我不能这样做。此外,我还要将此应用程序提供给其他用户,他们不应该使用这个技巧。 - asdf
4
你不理解:在C++代码的开头,可以调用setrlimit函数。这个函数可以被用来设定资源限制。请注意,这里需要在程序开头进行设置,而不是在系统级别上进行更改。 - F'x

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接