一 、Valgrind简介
Valgrind是运行在Linux上一套基于仿真技术的程序调试和分析工具,是公认的最接近Purify的产品,它包含一个内核——一个软件合成的CPU,和一系列的小工具,每个工具都可以完成一项任务——调试,分析,或测试等。Valgrind可以检测内存泄漏和内存越界,还可以分析cache的使用等,灵活轻巧而又强大。
二、 Valgrind概观
Valgrind的最新版是3.2.3,该版本包含下列工具:
2.1、Memcheck:
是一个内存错误探测器。检查程序中的内存问题,如泄漏、越界、非法指针等。它能够纠正你的程序中的错误,特别是用C和C++编写的程序。
2.2、Callgrind:
是一个call-graphgenerating cache profiler。检测程序代码覆盖,以及分析程序性能。它的功能与Cachegrind有些重复,但也收集了一些Cachegrind没有的信息。
2.3、Cachegrind:
是一个cache和分支预测分析器(a cache and branch-prediction profiler)。分析CPU的cache命中率、丢失率,用于进行代码优化。它帮助你使得你的程序跑的更快。
2.4、Helgrind:
是一个线程错误探测器。用于检查多线程程序的竞态条件。它帮助你纠正你的多线程程序。
2.5、Massif:
是一个堆分析器。堆栈分析器,指示程序中使用了多少堆内存等信息。它帮助你使得你的程序使用更少的内存。
2.6、Lackey:
是一个示例工具,它主要用来说明一些instrumentation的基本功能。
2.7、Nulgrind:
是最小化的Valgrind工具,它不做任何分析或instrumentation,仅用于testing目的。
2.8、DRD:
也是一个线程错误探测器。它跟Helgrind是相似的,但使用不同的分析技术,所以可能能够发现不同的问题。
2.9、DHAT:
是一个不同类型的堆分析器。它帮助你了解块生命周期,块利用,和布局失效(layout inefficiencies)。
2.10、SGcheck:
是一个实验性的数据,它能够探测stack和全局数组的越界。它的功能是Memcheck的补充,SGcheck能找到Memcheck不能找到的错误,反之也是如此。
2.11、BBV:
是一个实验性的SimPoint基本的块向量产生器。它用于计算机体系结构研究和开发。
三、 Valgrind工具详解
3.1、Memcheck
最常用的工具,用来检测程序中出现的内存问题,所有对内存的读写都会被检测到,一切对malloc、free、new、delete的调用都会被捕获。所以,它能检测以下问题:
1、对未初始化内存的使用;
2、读/写释放后的内存块;
3、读/写超出malloc分配的内存块(读/写内存越界);
4、读/写不适当的栈中内存块;
5、内存泄漏,指向一块内存的指针永远丢失;
6、不正确的malloc/new/new[]和free/delete/delete[]匹配;
7、memcpy()相关函数中的dst和src指针重叠。
这些问题往往是C/C++程序员最头疼的问题,Memcheck能在这里帮上大忙。
调用选项:
--leak-check=<no|summary|yes|full> [default: summary]
当这个选项打开时,在客户程序结束时查找内存泄漏。内存泄漏意味着有用malloc分配内存块,但是没有用free释放,而且没有指针指向这块内存。这样的内存块永远不能被程序释放,因为没有指针指向它们。如果设置为summary,Valgrind会报告有多少内存泄漏发生了。如果设置为full或yes,Valgrind给出每一个独立的泄漏的详细信息。
--show-reachable=<yes|no> [default: no]
当这个选项关闭时,内存泄漏检测器只显示没有指针指向的内存块,或者只能找到指向块中间的指针。当这个选项打开时,内存泄漏检测器还报告有指针指向的内存块。这些块是最有可能出现内存泄漏的地方。你的程序可能,至少在原则上,应该在退出前释放这些内存块。这些有指针指向的内存块和没有指针指向的内存块,或者只有内部指针指向的块,都可能产生内存泄漏,因为实际上没有一个指向块起始的指针可以拿来释放,即使你想去释放它。
--leak-resolution=<low|med|high>[default: low]
在做内存泄漏检查时,确定memcheck将怎么样考虑不同的栈是否是相同的情况。当设置为low时,只需要前两层栈匹配就认为是相同的情况;当设置为med,必须要四层栈匹配,当设置为high时,所有层次的栈都必须匹配。
对于hardcore内存泄漏检查,你很可能需要使用--leak-resolution=high和--num-callers=40或者更大的数字。注意这将产生巨量的信息,这就是为什么默认选项是四个调用者匹配和低分辨率的匹配。注意--leak-resolution= 设置并不影响memcheck查找内存泄漏的能力。它只是改变了结果如何输出。
--freelist-vol=<number>[default: 5000000]
当客户程序使用free(C中)或者delete(C++)释放内存时,这些内存并不是马上就可以用来再分配的。这些内存将被标记为不可访问的,并被放到一个已释放内存的队列中。这样做的目的是,使释放的内存再次被利用的点尽可能的晚。这有利于memcheck在内存块释放后这段重要的时间检查对块不合法的访问。
这个选项指定了队列所能容纳的内存总容量,以字节为单位。默认的值是5000000字节。增大这个数目会增加memcheck使用的内存,但同时也增加了对已释放内存的非法使用的检测概率。
--workaround-gcc296-bugs=<yes|no>[default: no]
当这个选项打开时,假定读写栈指针以下的一小段距离是gcc 2.96的bug,并且不报告为错误。距离默认为256字节。注意gcc 2.96是一些比较老的Linux发行版(RedHat 7.X)的默认编译器,所以你可能需要使用这个选项。如果不是必要请不要使用这个选项,它可能会使一些真正的错误溜掉。一个更好的解决办法是使用较新的,修正了这个bug的gcc/g++版本。
--partial-loads-ok=<yes|no>[default: no]
控制memcheck如何处理从地址读取时字长度,字对齐,因此哪些字节是可以寻址的,哪些是不可以寻址的。当设置为yes是,这样的读取并不抛出一个寻址错误。而是从非法地址读取的V字节显示为未定义,访问合法地址仍然是像平常一样映射到内存。
设置为no时,从部分错误的地址读取与从完全错误的地址读取同样处理:抛出一个非法地址错误,结果的V字节显示为合法数据。注意这种代码行为是违背ISO C/C++标准,应该被认为是有问题的。如果可能,这种代码应该修正。这个选项应该只是做为一个最后考虑的方法。
--undef-value-errors=<yes|no> [default: yes]
控制memcheck是否检查未定义值的危险使用。当设为yes时,Memcheck的行为像Addrcheck(一个轻量级的内存检查工具,是Valgrind的一个部分),它并不检查未定义值的错误。如果你不希望看到未定义值错误,可以使用这个选项。
3.2、Callgrind
和gprof类似的分析工具,但它对程序的运行观察更是入微,能给我们提供更多的信息。和gprof不同,它不需要在编译源代码时附加特殊选项,但加上调试选项是推荐的。Callgrind收集程序运行时的一些数据,建立函数调用关系图,还可以有选择地进行cache模拟。在运行结束时,它会把分析数据写入一个文件。callgrind_annotate可以把这个文件的内容转化成可读的形式。
Callgrind收集程序运行时的一些数据,函数调用关系等信息,还可以有选择地进行cache模拟。在运行结束时,它会把分析数据写入一个文件。callgrind_annotate可以把这个文件的内容转化成可读的形式。
一般用法:
$valgrind --tool=callgrind ./sec_infod
会在当前目录下生成callgrind.out.[pid],如果我们想结束程序, 可以
$killall callgrind
然后我们可以用
$callgrind_annotate --