如何在Linux中确定程序的堆栈大小?

7

如何确定Linux程序的当前堆栈大小?

据说Linux每个程序的堆栈大小为8 MB,但是当您使用cat /proc//mmap时会显示不同的大小。

另外,如何确定关联线程的堆栈大小?因为据说线程有自己的私有堆栈。

3个回答

6

如果您只想知道当前堆栈大小,可以在main()函数的顶部声明一个变量,获取其地址,并将其与在定义“current”时声明的变量的地址进行比较。差异应该是堆栈增长的大致大小。

如果您想知道为堆栈保留了多少内存,则可以检查/proc/[pid]/maps,其中有一个标记为[stack]的区域。例如,我的atd进程具有:

7fff72a41000-7fff72a56000 rw-p 00000000 00:00 0                          [stack]
0175b000-0177c000 rw-p 00000000 00:00 0                                  [heap]

这个小技巧可以帮助你了解程序使用的最大堆栈大小。

一位朋友向我分享了一个小技巧,当我想知道我的程序使用的最大堆栈大小时,可以采用以下方法。我在这里介绍一下,以防有人觉得有用 :)

1)在main()函数开始附近的一个函数中,使用alloca()或一个很长的数组,在你预计可能使用的堆栈上刻上0xDEADBEEF或其他类似不太可能出现的常量。这段内存将在小函数返回时被“释放”。

2)在main的末尾再次使用alloca()来获取一块内存区域,并“搜索”其中包含你之前刻上的魔法常量的位置(你可以尝试找到其中的前64个来跳过已分配但从未使用的内存区域),指针停留的位置即表示你的最大堆栈使用量。

虽然不完美,但对我当时做的事情很有用!


如果虚拟机页面在“释放”的堆栈区域被内核回收并重新分配,那么这个“巧妙的技巧”不会失败吗? - Dipstick
我不相信内核会尝试重新获取堆栈区域。事实上,我认为堆栈本身只是编译器/汇编器/标准库之间的一个(极其普遍的)约定,因此我不确定内核能否充分证明它是安全的可回收的。 - Steven Schlansker
我不明白为什么回收栈顶以上的未使用页面会有任何“不安全”的问题(当然,前提是机器支持需求分页——大多数能运行Linux的机器都支持)。显然,如果内核回收了当前栈顶以上的所有页面,那么就需要处理很多不必要的页面错误,但如果内存不足,则可能只需要保留一两个备用页面。将“释放”的栈页面换入和换出磁盘毫无意义。 - Dipstick
堆栈“惯例”是如此广泛,以至于即使操作系统也会在异常处理中使用它,因此理论上它可以被释放(将其分页没有意义)。但是,即使如此,你的应用程序需要一个 精确 的页面大小倍数的机会有多大呢?在几乎所有情况下,最后一页顶部都会留下一些无效的数据,因此这种技巧几乎总是有效的。 - zildjohn01
主函数的栈帧是堆栈中的第一个吗?main(int argc, char**argv)呢?那么,主函数的参数存储在哪里? - olegst

3

正如Steven所建议的那样,你的线程保留的堆栈大小和线程当前使用的堆栈之间存在差异。

如果你想知道一个线程为多少内存保留,可以使用pthread属性。

pthread_attr_t attr;
size_t stacksize;

pthread_attr_init(&attr);
pthread_attr_getstacksize(&attr, &stacksize); 

printf("%u\n", stacksize); 

这将打印创建一个线程时保留的默认堆栈大小。对我而言,它是8 Mb。
您可以通过使用pthread_attr_setstacksize()并将attr结构作为2个参数传递给pthread_create函数来更改此设置。
编辑:也许您还应该注意懒惰分配问题。除非您在此内存空间中读取或写入所有位置,否则您的8 Mb虚拟空间不会使用8Mb物理内存空间。

0

虽然有多种方法可以手动查询Linux中的这些信息,例如在/proc/等地方。但我最近发现stackusage非常方便,它拦截线程的创建并显示实际使用情况,非常准确。对于单线程应用程序也适用。


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