使用setrlimit设置堆栈大小失败



我在Ubuntu 18.04上使用gcc 10.1。当定义一个大的堆栈分配变量时,我会遇到segfault,尽管我的堆栈似乎足够大,可以容纳它

#include <iostream>
#include <array>
#include <sys/resource.h>
using namespace std;
int main() {
if (struct rlimit rl{1<<28, 1l<<32}; setrlimit(RLIMIT_STACK, &rl))
cout << "Can not set stack size! errno = " << errno << endl;
else
cout << "Stack size: " << rl.rlim_cur/(1<<20) << "MiB to " << rl.rlim_max/(1<<20) << "MiBn";
array<int8_t, 100'000'000> a;
cout << (int)a[42] << endl;
}

当使用gcc编译时,它会分段故障,但当使用clang 11.0.1编译时运行良好,并输出:

Stack size: 256MiB to 4096MiB
0

编辑

Clang正在排除a的分配。这里有一个更好的例子:

#include <iostream>
#include <array>
#include <sys/resource.h>
using namespace std;
void f() {
array<int8_t, 100'000'000> a;
cout << (long)&a[0] << endl;    
}
int main()
{
if (struct rlimit rl{1<<28, 1l<<32}; setrlimit(RLIMIT_STACK, &rl))
cout << "Can not set stack size! errno = " << errno << endl;
else
cout << "Stack size: " << rl.rlim_cur/(1<<20) << "MiB to " << rl.rlim_max/(1<<20) << "MiB" << endl;
array<int8_t, 100'000'000> a; // line 21
cout << (long)&a[0] << endl;  // line 23
f();
}

您可以在以下位置找到:https://wandbox.org/permlink/XMaGFMa7heWfI9G8.当第21行和第23行被注释掉时,它运行良好,但segfault除外。

使用proc(5(、pmap(1(和strace(1(了解计算机的局限性。

array<int8_t, 100'000'000> a;

调用堆栈上需要大约100M字节的空间,通常限制在几兆字节(甚至可能是您的Linux内核,但我不确定(

也可以在您的终端中尝试cat /proc/$$/limits。我的

Limit                     Soft Limit           Hard Limit           Units     
Max cpu time              unlimited            unlimited            seconds   
Max file size             unlimited            unlimited            bytes     
Max data size             unlimited            unlimited            bytes     
Max stack size            8388608              unlimited            bytes     

编译器之间的行为差异可能归因于各种优化(例如,某些C++标准(如n4849(允许的优化(。一个足够聪明的编译器可以在函数f中只使用几个单词来表示a(例如,因为它可能会发现,通过一些抽象的解释技术,位置a[1024]a[99999999]是无用的(。

如果使用最近的GCC(例如GCC 10(进行编译,则可以将其调用为g++ -O -Wall -Wextra -fanalyzer -Wstack-usage=2048以获得有用的警告。另见CHARIOT&DECODER项目。

在实践中,对大数据使用动态分配(例如,具有mmap(2(和智能指针的布局new(

对于一个真实的应用程序,可以考虑编写GCC插件来获得特别的警告。

或者至少用g++ -O2 -fverbose-asm -S foo.cc编译源代码foo.cc,查看生成的foo.s内部,用clang++重复:生成的汇编文件不同。

最新更新