【问题标题】:Measure static, heap and stack memory ? (c++, Linux - Centos 7)测量静态、堆和堆栈内存? (c++, Linux - Centos 7)
【发布时间】:2018-08-01 07:28:59
【问题描述】:

我想分别测量堆栈、堆和静态内存,因为我对每一个都有一些限制。

为了测量堆内存,我使用了 valgrind->massif 工具。 Massif 也应该可以测量堆和堆栈内存,但它显示出奇怪的结果:

  • 没有 --stacks=yes 的最后一个快照提供了 total(B)=0、有用堆(B)=0、extra-heap(B)=0(所以一切都很好)

  • 使用 --stacks=yes 的最后一个快照提供了 total(B)= 2,256、有用堆 (B)=1,040、extra-heap(B)=0、stacks(B)=1,208(显示内存泄漏,即使它是相同的命令和相同的二进制测试...不知道为什么...)

所以最后我需要一个工具来测量 c++ 二进制文件使用的堆栈和静态内存,欢迎提供一些帮助:)

感谢您的帮助!

----------- 编辑 --------------

关于 Basile Starynkevitch 的评论,为了解释我对静态、堆栈和堆内存的含义,我从 Dmalloc 库文档中获取了它:

  • 静态数据是其存储空间编译到程序中的信息。

    /* global variables are allocated as static data */
    int numbers[10];
    
    main()
    {
            …
    }
    
  • 堆栈数据是在运行时分配的数据,用于保存函数内部使用的信息。这些数据由系统在称为堆栈空间的空间中管理。

    void foo()
    {
            /* if they are, the parameters of the function are stored in the stack */
            /* this local variable is stored on the stack */
            float total;
            …
    }
    
    main()
    {
        foo();
    }
    
  • 堆数据也在运行时分配,为程序员提供动态内存能力。

    main()
    {
        /* the address is stored on the stack */
        char * string;
        …
    
        /*
         * Allocate a string of 10 bytes on the heap.  Store the
         * address in string which is on the stack.
         */
        string = (char *)malloc(10);
        …
    
        /* de-allocate the heap memory now that we're done with it */
        (void)free(string);
        …
    }
    

【问题讨论】:

  • 阅读proc(5)。对于进程 1234,考虑在终端中运行 cat /proc/1234/maps
  • 我试了一下。但是我遇到了一些问题:(1)我的二进制文件是做路径规划的。所以运行大约需要 50-400 毫秒。因此,我不能真正使用 PID 来检查实时使用的内容。 (2) 它不提供使用的内存堆栈/堆的数量,只提供一个地址。我不知道如何处理这个地址
  • 在你的程序中,你可能会读到/proc/self/maps,就像here一样
  • 而且我不确定“堆”内存或“静态”内存是否像您希望的那样容易定义......
  • 我编辑了我的问题以解释我所说的堆、静态和堆栈的含义

标签: c++ valgrind heap-memory stack-memory static-memory-allocation


【解决方案1】:

顺便说一句,我在你回答之前找到了它:

  • 要测量堆内存使用 valgrind -> massif

  • 要测量静态内存,请在二进制文件上使用 bash 函数 size

  • 要测量堆栈,可以使用stackusage

它给了我想要的所有数据

【讨论】:

  • 但这些可能不是您想要的,因为您对堆内存、静态内存、堆栈的概念非常幼稚。
  • 我也认为你应该用/proc/*/maps来衡量
  • 顺便说一句,要使用 /proc/self/maps 测量堆栈,我计算了以下行提供的两个地址之间的差异“7ffc5d8c0000-7ffc5d8e3000 rw-p 00000000 00:00 0 [堆栈]”。但是我得到了一些我觉得有点太大的东西。这是正确的做法吗?
【解决方案2】:

我想分别测量堆栈、堆和静态内存,因为我对每一个都有一些限制。

我无法想象为什么您对每个都有单独的 约束。他们都坐在virtual memory!顺便说一句,您可以使用 setrlimit(2) 设置限制(可能来自调用 shell 进程,例如使用 bash ulimit 内置)。

如果您考虑流程的实际virtual address space,您的定义是幼稚的。

顺便说一句,proc(5) 使您能够查询该空间,例如在程序内部使用/proc/self/maps,如here(或/proc/1234/maps 查询pid 1234 的进程,可能从终端)。您还可以使用/proc/self/status/proc/self/statm(顺便说一句,在终端中尝试cat /proc/self/mapscat /proc/$$/maps)。在 Linux 上,您还可以使用 mallinfo(3)malloc_stats(3) 获取有关内存分配统计信息的信息。

静态数据可能位于程序的data segment(或BSS 段)中。但是线程本地空间呢?这些数据段还包含各种库内部的数据,特别是 C 标准库libc.so(这算不算?)。当然堆栈段通常比实际使用堆栈(从“底部”到当前%esp寄存器)更大(因为页面对齐)。一个多threaded 进程有几个 堆栈(和堆栈段),每个线程一个。

堆栈数据当然在调用堆栈中,其中包含许多其他内容(返回地址、间隙、溢出的寄存器),而不仅仅是 automatic variables(其中一些仅位于寄存器中或由编译器优化,没有消耗任何堆栈槽)。他们算吗?此外,来自crt0(调用您的main)的启动代码可能会使用一点堆栈空间(这算不算?)...

堆分配的数据(它可以从各种库分配,甚至从动态链接器分配)不仅包含您的程序从malloc(和朋友)获得的内容,还包含必要的开销。这算不算?那么memory-mapped files 呢?他们应该怎么算?

我建议查询实际的虚拟地址空间(例如,通过阅读 /proc/self/maps 或使用 pmap(1)...),但您得到的结果与您所要求的不同。

【讨论】:

  • 对不起。我对每一个都没有真正的限制,但我的老板希望我衡量每一个,以了解什么消耗了什么以及我们是否可以嵌入我们的代码。对于“静态内存”,我直接在二进制文件上使用 bash 函数 size。我知道未初始化的静态变量不计入显示的内容中。为了分析堆内存,我使用 valgrind。多亏了这一点,我得到了最大的分配峰值以及分配和释放的内存总量。但由于我是初学者,您“睁大了眼睛”并感谢您的帮助!
猜你喜欢
  • 2012-09-06
  • 2017-01-04
  • 1970-01-01
  • 1970-01-01
  • 2021-06-14
  • 2019-05-17
  • 2011-04-25
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多