【linux】Valgrind工具集详解(十一):Massif(堆分析器)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u010168781/article/details/83788559

一、概述

Massif是一个堆分析器。它统计程序使用的堆内存大小(由malloc等函数分配的内存)。默认情况下不统计程序所使用的所有内存,如果想统计所有内存,需要使用选项–pages-as-heap=yes。

堆分析可以帮助减少程序使用的内存。如果分配的内存还没有释放并且指针也在,这种情况对于Memcheck(内存泄漏检查器)来说不算错误。但是随着时间内存增加,这也算内存泄漏,Massif可以帮助识别这些泄漏。

重要的是,Massif不仅会报告程序正在使用多少堆内存,还会提供非常详细的信息,来指明这些内存是由程序中哪部分分配的。

二、使用

0、源码
#include <stdio.h>
#include <stdlib.h>

int main()
{
    int *x = (int *)malloc(sizeof(int)*10);
    free(x);
    x = (int *)malloc(sizeof(int)*10);
    int *y = (int *)malloc(sizeof(int)*10);
    free(y);
    free(x);
    return 0;
}
1、 编译

gcc编译源码时,添加 -g 选项,Massif对编译优化没有要求。

2、分析

执行命令:valgrind --tool=massif --time-unit=B ./a.out,./a.out是可执行程序,执行完毕后,massif将分析数据保存在在当前目录下,文件格式是massif.out.PID,PID是进程号

3、查看

使用 ms_print massif.out.PID查看分析结果,内容如下

--------------------------------------------------------------------------------
Command:            ./a.out
Massif arguments:   --time-unit=B
ms_print arguments: massif.out.5262
--------------------------------------------------------------------------------
     B
  112^                                                ############            
     |                                                #                       
     |                                                #                       
     |                                                #                       
     |                                                #                       
     |                                                #                       
     |                                                #                       
     |                                                #                       
     |                                                #                       
     |                                                #                       
     |            @@@@@@@@@@@@            ::::::::::::#           ::::::::::: 
     |            @                       :           #           :           
     |            @                       :           #           :           
     |            @                       :           #           :           
     |            @                       :           #           :           
     |            @                       :           #           :           
     |            @                       :           #           :           
     |            @                       :           #           :           
     |            @                       :           #           :           
     |            @                       :           #           :           
   0 +----------------------------------------------------------------------->B
     0                                                                     336

Number of snapshots: 9
 Detailed snapshots: [2, 6 (peak)]
--------------------------------------------------------------------------------
  n        time(B)         total(B)   useful-heap(B) extra-heap(B)    stacks(B)
--------------------------------------------------------------------------------
  0              0                0                0             0            0
  1             56               56               40            16            0
  2             56               56               40            16            0
71.43% (40B) (heap allocation functions) malloc/new/new[], --alloc-fns, etc.
->71.43% (40B) 0x40058D: main (main.c:6)
--------------------------------------------------------------------------------
  n        time(B)         total(B)   useful-heap(B) extra-heap(B)    stacks(B)
--------------------------------------------------------------------------------
  3            112                0                0             0            0
  4            168               56               40            16            0
  5            224              112               80            32            0
  6            224              112               80            32            0
71.43% (80B) (heap allocation functions) malloc/new/new[], --alloc-fns, etc.
->35.71% (40B) 0x4005A7: main (main.c:8)
| 
->35.71% (40B) 0x4005B5: main (main.c:9)
| 
->00.00% (0B) in 1+ places, all below ms_print's threshold (01.00%)
--------------------------------------------------------------------------------
  n        time(B)         total(B)   useful-heap(B) extra-heap(B)    stacks(B)
--------------------------------------------------------------------------------
  7            280               56               40            16            0
  8            336                0                0             0            0
4、 说明

<1> 坐标图详解
坐标图中“:”表示普通快照、“@”表示详细快照、“#”表示峰值快照;坐标图左下角的“Number of snapshots: 9”是快照总数量、
“Detailed snapshots: [2, 6 (peak)]”是详细快照列表,peak表示峰值快照。
<2>普通快照详解

-<a>-------<b>------------ <c>----------<d>---------------<e>-------------<f>--
  n        time(B)         total(B)   useful-heap(B) extra-heap(B)    stacks(B)
--------------------------------------------------------------------------------
  0          0                0                0             0            0
  1          56               56               40            16           0

<a>快照编号;
<b>快照采集时间,(B)括号中的B表示时间单位是字节,在执行Massif分析时,添加了参数–time-unit=B;
<c>总内存消耗量;
<d>可用堆内存的字节数,即程序申请内存时,指定的数量;
<e>额外堆内存的字节数,包括管理内存增加的字节(默认是8,可以使用–heap-admin选项来重新设定)和为了对齐多出的字节(通常是8或16,可以使用–alignment选项来重新设定);
<f>栈的大小,默认情况下,栈分析是关闭的,因为它会大大降低Massif的速度。因此,示例中的表示栈大小的列为零(可以使用–stacks=yes选项打开栈分析 )。

<3>详细快照详解
除了基本计数(和普通快照一样)之外,它还提供了一个分配树,准确地指出这些堆内存是由哪些代码分配的:

71.43% (40B) (heap allocation functions) malloc/new/new[], --alloc-fns, etc.
->71.43% (40B) 0x40058D: main (main.c:6)

第一行表示分配的函数;
第二行表示在源码中的位置
<4>峰值快照详解
峰值快照和详细快照一样,不再赘述

5、警告

如果程序有分支(有父子进程),需要使用–massif-out-file选项来指定保存文件名,并且在文件名中添加“%p”,来分别保存父子进程的分析结果,否则会记录到一个文件中,导致ms_print无法读取。

6、完整内存分析

默认情况下,Massif只分析堆内存,即函数malloc、 calloc、 realloc、memalign、new、new[]和一些其他类似的函数分配的内存。这意味着它不直接分析较低级别的系统调用,如 mmap、 mremap、brk。它也不分析代码段、数据段和BSS段(约等于全局区域)的大小。因此Massif分析报告的数字可能远远小于top等程序工具所报告的数字。
如果想测量程序使用的所有内存,可以使用–pages-as-heap=yes选项,启用此选项后,Massif通过把mmap和类似系统调用函数分配的每个“页面”都被视为一个不同于常规堆块的“块”来分析。这意味着代码段、数据段、BSS段和栈内存都被测量。
注意:不允许–stacks=yes和–pages-as-heap=yes同时出现。
设置–pages-as-heap=yes后,ms_print的输出大部分不变。一个区别是每个详细快照的开头由:

(heap allocation functions) malloc/new/new[], --alloc-fns, etc.

变成:

(heap allocation functions) malloc/new/new[], --alloc-fns, etc.

三、Massif命令行选项

–heap=<yes|no> [default: yes]
是否启动对分析,默认是yes(启动)。

–heap-admin= [default: 8]
设置每个块的管理字节数,属于快照详解中额外字节数

–stacks=<yes|no> [default: no]
是否启动栈内存分析,启动后会减慢Massif,默认是关闭。

–pages-as-heap=<yes|no> [default: no]
是否检查程序所使用的全部内存,即代码段、数据段、BSS段和栈内存,参见上面的分析。
注意:不允许–stacks=yes和–pages-as-heap=yes同时出现。

–depth= [default: 30]
设置详细快照中分配树的最大深度。增加它将使Massif运行得更慢,使用更多内存,并产生更大的输出文件。

–alloc-fn=
指定封装了堆分配函数的函数名。
注意:
如果malloc1封装了函数malloc,并且malloc2又封装了malloc1,则只指定 --alloc-fn=malloc2将不起作用。还需要指定–alloc-fn=malloc1;
如果是C++,必须完整地写入重载的函数名,并放到单引号内,如:

--alloc-fn ='operator new(unsigned,std :: nothrow_t const&)'

–ignore-fn=
指定堆分析时,忽略的函数,如malloc、new或–alloc-fn指定的函数等,编写C ++函数名的规则与–alloc-fn相同。

–threshold=<m.n> [default: 1.0]
设置详细快照中分配树是否打印出来代码详细位置的阈值,低于该阈值时,不打印,默认是1.0%,如:

99.76% (10,000B) (heap allocation functions) malloc/new/new[], --alloc-fns, etc.
->79.81% (8,000B) 0x80483C2: g (example.c:5)
| ->39.90% (4,000B) 0x80483E2: f (example.c:11)
| | ->39.90% (4,000B) 0x8048431: main (example.c:23)
| |   
| ->39.90% (4,000B) 0x8048436: main (example.c:25)
|   
->19.95% (2,000B) 0x80483DA: f (example.c:10)
| ->19.95% (2,000B) 0x8048431: main (example.c:23)
|   
->00.00% (0B) in 1+ places, all below ms_print's threshold (01.00%)

–peak-inaccuracy=<m.n> [default: 1.0]
针对峰值快照的选项,当内存增加到比前一个峰值至少1.0%(默认值)时,才将这时的内存进行详细的快照,更新为新的峰值。否则内存增加一点点就记录为峰值会影响Massif的性能。

–time-unit=<i|ms|B> [default: i]
设置Massif分析的时间单位。有三种:按照程序运行的指令数、按照时间(毫秒)、按照申请、释放的字节数变化。最后一种对于小程序和测试时非常有用,因为它的复现性比较好。

–detailed-freq= [default: 10]
设置详细快照的频率。当设置为1(–detailed-freq=1)时,每个快照都被记录成详细的。

–max-snapshots= [default: 100]
设置最大快照数。如果设置为N,对于除非常小的程序(程序小到它全部快照数不超过默认值)外,最终的快照数将介于N / 2和N之间。

–massif-out-file= [default: massif.out.%p]
将Massif分析数据写入指定file 而不是默认输出文件 massif.out.。
文件名中可以添加 %p和%q用来加入进程ID和%q后指定环境变量的内容。
比如,有环境变量“HELLO”,可以使用下面的命令格式将进程ID和该环境变量加入到文件名中:

valgrind --tool=massif --massif-out-file=hello.%p.%q{HELLO} ./a.out

如果%q后没有环境变量,将报错:valgrind: --massif-out-file: expected ‘{’ after ‘%q’,错误的命令格式如下:

valgrind --tool=massif --massif-out-file=hello.%p.%q ./a.out

如果%q后面的环境变量不存在,将报错:valgrind: --massif-out-file: environment variable HELLO is not set

四、ms_print命令行选项

-h --help
显示帮助信息。

–version
显示版本号。

–threshold=<m.n> [default: 1.0]
与Massif的–threshold选项相同,但在分析后而不是在分析期间使用。

–x=<4…1000> [default: 72]
设置图表的宽度。

–y=<4…1000> [default: 20]
设置图表的高度。

猜你喜欢

转载自blog.csdn.net/u010168781/article/details/83788559
今日推荐