【问题标题】:How to determine Stack size of a Program in linux?如何确定Linux中程序的堆栈大小?
【发布时间】:2010-12-13 07:45:03
【问题描述】:

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

据说在linux中每个程序的堆栈大小为8 MB,但是当你使用 cat /proc//mmap 它显示不同的大小。

另外,如何确定相关线程的堆栈大小?既然说线程有自己的私有栈?

【问题讨论】:

    标签: linux multithreading stack-size


    【解决方案1】:

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

    如果您想知道为堆栈保留了多少内存,可以查看 /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 个的第一个块或跳过可能已分配但从未使用过的内存区域),并且该指针所在的位置指示您的最大堆栈使用量。

    不完美,但对我正在做的事情很有用!

    【讨论】:

    • 如果“已释放”堆栈区域中的 VM 页面被内核回收并重新分配,“巧妙的技巧”会不会失败?
    • 我不相信内核会尝试回收堆栈区域。事实上,我认为堆栈本身只是编译器/汇编器/标准库之间的(非常普遍的)约定,所以我不确定内核是否可以充分“证明”它可以安全回收。
    • 我不明白回收堆栈顶部上方的任何未使用页面是如何“安全”的(当然假设机器支持按需分页 - 大多数支持 linux 的机器都支持)。显然,如果当前堆栈顶部之上的所有页面都被内核回收,那么将有很多不必要的页面错误需要处理,但如果内存不足,可能只需要保留一两个备用页面。在磁盘内外交换“已释放”的堆栈页面完全没有意义。
    • 堆栈“约定”非常普遍,甚至操作系统也将其用于异常处理,因此理论上它可以被释放(将其分页没有意义)。但是,即使是这样,您的应用需要 精确 倍页面大小的可能性有多大?在几乎所有情况下,最后一页的顶部都会有一些死牛肉的残留物,所以这个技巧应该几乎总是有效的。
    • main的栈帧是栈的第一个吗? main(int argc, char**argv) 怎么样?那么 main 的参数在哪里呢?
    【解决方案2】:

    正如 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 的物理内存空间,除非您在此内存空间中的任何位置进行读写。

    【讨论】:

      【解决方案3】:

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2015-07-09
        • 2010-09-15
        • 1970-01-01
        • 2012-09-09
        • 2016-07-15
        • 2014-09-24
        • 2014-06-26
        相关资源
        最近更新 更多