C++ UNIX:UNIX中的堆栈大小(ulimit-s)应该是多少?
如何在UNIX中计算程序所需的最小堆栈大小,使程序永远不会崩溃 假设我的程序是C++ UNIX:UNIX中的堆栈大小(ulimit-s)应该是多少?,c++,c,multithreading,unix,C++,C,Multithreading,Unix,如何在UNIX中计算程序所需的最小堆栈大小,使程序永远不会崩溃 假设我的程序是 int main() { int number; number++; return 0; } 1) 此程序运行所需的堆栈大小是多少?如何计算 2) 我的Unix系统提供了ulimit-s 512000。我的小程序真的需要这个值吗 3) 如果我有一个具有多线程的大程序,大约500个函数,包括一些库、宏、动态分配的内存等,那么需要多少堆栈大小呢?没有神奇的方法可以告
int main()
{
int number;
number++;
return 0;
}
1) 此程序运行所需的堆栈大小是多少?如何计算
2) 我的Unix系统提供了ulimit-s 512000
。我的小程序真的需要这个值吗
3) 如果我有一个具有多线程的大程序,大约500个函数,包括一些库、宏、动态分配的内存等,那么需要多少堆栈大小呢?没有神奇的方法可以告诉你的程序在堆栈上需要多少空间。这取决于代码实际在做什么。无限(或非常深)递归将导致堆栈溢出,即使程序似乎什么也不做 作为示例,请参见以下内容:
$ ulimit
unlimited
$ echo "foo(){foo();} main(){foo();}" | gcc -x c -
$ ./a.out
Segmentation fault (core dumped)
main
之前的部分。但它不太可能超过几十个字节,可能一次超过几百个字节。因为任何现代操作系统中的最小堆栈大小都是“一页”=4KB,这应该很容易适应李>
void func()
{
int x, y, z;
float w;
...
}
此函数占用大约16字节的堆栈,加上调用函数的一般开销,通常为1-3个“机器字”(32位机器上为4-12字节,64位机器上为8-24字节)
此函数将占用40000字节的堆栈空间。显然,不需要对该函数进行多次递归调用就可以耗尽堆栈 大多数人依赖于堆栈是“大”的,而他们的程序不使用所有堆栈,这仅仅是因为堆栈的大小设置得太大,以至于程序很少会因为堆栈空间不足而失败,除非他们使用具有自动存储持续时间的超大阵列 这是一个工程故障,从某种意义上说,它不是工程故障:一个已知且基本上可以预防的完全故障源是不可控的 通常,很难计算程序的实际堆栈需求。特别是当存在递归时,编译器通常无法预测一个例程将被递归调用多少次,因此它无法知道该例程将需要多少次堆栈空间。另一个复杂问题是对运行时准备的地址的调用,例如对虚拟函数的调用或通过其他函数指针的调用 不过,编译器和链接器可以提供一些帮助。对于任何使用固定堆栈空间的例程,理论上,编译器都可以提供这些信息。一个例程可能包括执行或未执行的块,每个块可能有不同的堆栈空间要求。这会干扰编译器为例程提供固定的数字,但编译器可能会单独提供关于每个块的信息和/或例程的最大值 理论上,链接器可以检查调用树,如果调用树是静态的且不是递归的,则可以为链接程序提供最大的堆栈使用量。它们还可以提供沿着特定调用子链的堆栈使用(例如,从一个例程到导致递归调用同一例程的调用链),这样人类就可以将算法知识应用到子链堆栈使用的倍数上,最大次数为递归调用子链的次数 我没有见过具有这些功能的编译器或链接器。这表明,开发这些功能几乎没有经济动机 有时堆栈使用信息很重要。操作系统内核可能有一个比用户进程更有限的堆栈,因此应该计算内核代码的最大堆栈使用量(作为一个良好的工程实践),以便可以适当地设置堆栈大小(或者重新设计代码以使用更少的堆栈) 如果您有计算堆栈空间需求的关键需求,可以检查编译器生成的汇编代码。在许多计算平台上的许多例程中,在例程开始时从堆栈指针中减去一个固定数字。在没有附加减法或“推”指令的情况下,这是例程的堆栈使用,不包括它调用的子例程使用的其他堆栈。但是,例程可能包含包含额外堆栈分配的代码块,因此必须仔细检查生成的汇编代码,以确保找到所有堆栈调整 例程还可能包含在运行时计算的堆栈分配。在计算堆栈空间非常关键的情况下,可以避免编写导致此类分配的代码(例如,避免使用C的可变长度数组特性) 一旦确定了每个例程的堆栈使用情况,就可以通过沿各种例程调用路径添加每个例程的堆栈使用情况(包括调用
main
之前运行的启动例程的堆栈使用情况)来确定程序的总堆栈使用情况
这种使用完整程序的堆栈计算通常比较困难,很少执行
您通常可以估计堆栈的使用情况
void func2()
{
int x[10000];
...
}