Valgrind是一个动态分析工具,能够自动检测许多内存管理问题、线程bug, 并且能够分析程序的状况。它内部支持多个工具集,包括内存错误检测器,线程错误检测器,缓存分析器、堆分析器等,默认使用的是内存检测器(memcheck), 它是使用最多的一个内存检测工具。当然,你也可以基于Valgrind自己建立新的工具。
Valgrind支持的平台有:
Valgrind是开源免费的软件,基于GNU General Public License, version 2。
一、快速入门
Valgrind工具集中最受欢迎的是memcheck, 它满足大部分的场景。memcheck能够检测内存相关的错误,并且是采用C/C++编译的程序,程序运行过程中奔溃或者不可预料的行为都可以使用Valgrind中的memcheck来进行检测。
使用Valgrind前,采用-g选项编译程序,这样memcheck才能够提取到具体的行号信息,同时可以使用-O0优化选项,但是如果使用-O1选项,那么显示的行号信息可能就不准确;不推荐使用-O2选项,如果使用的话,memcheck偶尔上报不是真的存在的未初始化的错误信息。
命令行一般的使用格式如下所示,–leak-check=yes是打开内存泄露的检测器。
下面提供一个C++例子,该例子有内存泄露和访问不存在地址的两个错误:
错误信息描述如下,表示访问不存在地址,第一行“Invalid write of size 4”表明什么类型错误,写数据到内存中,而该内存是不应该访问的。1066表示进程id号。如果错误的堆栈信息显示不够显示,那么可以加上选项–num-callers,再加上层级数量,比如–num-callers=20。
内存泄露的错误信息提示描述如下, 它会告诉你内存分配的位置,但是它不能告诉你内存为什么泄露。
一般有几种内存泄露的类型,比较重要的两种是definitely lost和possibly lost,definitely lost是确定内存泄露,需要修复它,possibly lost可能存在内存泄露,需要仔细确认。
另外memcheck比较经常会上报没有初始化值的信息,但是要定位到错误信息的根本原因是比较困难的,对此,可以添加参数–track-origins=yes来获取更多的信息,但是,这样会使得memcheck运行得更慢。
二、memcheck的错误信息
memcheck是内存错误的检测器,他可以检测C/C++常见的下列错误问题:
访问不应该访问的内存,例如堆溢出、栈溢出、访问已经释放的内存使用没有定义的值,例如值没有初始化不正确的释放堆内存,例如重复释放内存,malloc/new/new[] 和 free/delete/delete[]没有一一对应使用使用memcpy函数,源地址和目的地址重叠向内存分配函数中,传递一个不正确的参数,例如负数内存泄露接下来将通过几个例子来说明。
非法读写错误,例如读取已经释放内存的地址,为了获取更多的信息,可以加上–read-var-info=yes的选项。
使用没有定义的值,例如定义了变量,但是没有初始化,如果信息不够详细,可以添加参数–track-origins=yes来获取更多的信息。
如果没有初始化变量,就会显示“Conditional jump or move depends on uninitialised value”信息。
非法释放地址,例如重复释放内存。
重复释放内存就会提示“Invalid free()”信息。
调用申请和释放内存的方法不匹配,例如malloc申请内存,但是使用delete来释放,对某些系统来说是不允许的,因此,为了保证程序健壮,使用malloc,那么对应使用free; 使用new,那么对应使用delete; 使用new [], 那么对应使用delete []。
三、Valgrind调用QtCreator程序
mac系统通过QtCreator创建程序之后,也可以采用Valgrind在终端上检测QtCreator生成的程序。
首先进入QtCreator编译生成的文件目录。
接着选择build开头的目录,右键弹出的列表选择“服务”->”新建位于文件夹位置的终端窗口”来启动终端, 终端输入如下所示的命令来使用Valgrind测试QtCreator编译生成的程序JQtTestStudy.app。
四、局限性
Memcheck并不完美,它也会出现误报,但是它有99%的准确性,对于它提示的信息我们应该警惕。memcheck不能检测每一种内存错误,比如它不能检测到对静态分配或堆栈上的数组的超出范围的读写,但是它还是能够检测出使得你程序奔溃的错误,例如段错误segmentation fault。五、总结
程序开发过程中,可能会遇到崩溃的问题,如果代码量很多的时候,我们可能会使用gdb来查看coredump信息,但是有时候gdb的信息比较简单,没有更加详细的堆栈信息,那么就可以考虑使用Valgrind进行分析。最近,工作中遇到一个问题,程序运行过程中,会偶发崩溃问题,使用gdb查看coredump信息,显示是重复释放内存,但是堆栈信息很少,一直找不到位置,后来使用Valgrind来查看程序,仔细查看从Valgrind提供的堆栈信息,很快找到问题的位置,原因确实是重复释放内存。
温馨提示:Valgrind经常上报了很多错误提示信息,这个可能是同样一个地方调用了多次,所以,如果解决了一个地方的问题,错误提示信息就会全部消失,需要耐心仔细。