Valgrind使用小记

因为最近要测试一个C++工程的项目,所以先是了解了一下gtest,用gtest写了不少用例。发现gtest确实比较好用,类xUnit的框架上手很容易。写完测试的代码之后,功能性测试基本就告一段落了。
但由于是C++的程序,那内存的检查就不得不仔细做一下了。问了一下公司里的前辈,回答说:“用Valgrind吧,跑一下就知道了,很简单的”。就在这样的一个机会下接触了Valgrind,Valgrind是一套对C和C++程序进行调试和优化的工具,其中最有名也是最常用的工具就是Memcheck,它能够检查到很多内存相关的错误,如内存泄漏,不合法的操作等。

官网地址:http://valgrind.org/

一、安装

作为一款非常牛X的工具,安装怎么可能会费事呢。
Ubuntu下输入

sudo apt-get install valgrind
mac下就输入
brew install valgrind
搞定。 # 二、使用 使用起来其实也很简单,如果你之前运行程序的命令是:
myprog arg1 arg2

那么现在只需在前面加上:

valgrind --leak-check=yes myprog arg1 arg2

valgrind运行的时候默认使用的就是Memcheck工具,–leak-check选项是开启内存泄漏探测功能。

三、例子

其实从安装到使用只是输入了几个简单的命令而已,最重要的环节还是要查看和分析运行的结果。所以这里用一个简单的例子来说明一下。

首先是demo.cpp

#include

void f(void) {
int* x = (int*) malloc(10 * sizeof(int));
x[10] = 0;
}

int main(void) {
f();
return 0;
}

我们可以看到上面是一个简单的程序,里面有很明显的两个错误。不过如果你没有发现的话,还是加油学习吧。。。

下面就是把它编译一下生成可运行的程序:

g++ -o demo -g demo.cpp

记得编译的时候加上-g,这样的话在后面生成的日志文件中就会有错误发生的具体行数,便于调试。
之后就可以用valgrind来查看是否有内存相关的问题了。运行:

valgrind --leak-check=full --log-file=log.txt -v ./demo

这里的参数说明一下,–leak-check这个前面说过了,–log-file这个顾名思义就是把log存储到指定文件中,因为在运行的时候一般都会生成大量的log,存到一个文件里便于查看,-v这个参数就是输出一些辅助信息,便于之后问题定位。
运行之后,打开生成的日志文件查看。
日志文件里面会有一大堆信息,耐心的往下翻,然后我们就可以看到它报错的消息,这里有个小敲门,就是日志每行前面都会有一串数字,例如–32063–或者==32063==,这个数字是表示进程的id,不过以 – 开头的一般不需要关注,只需要关注以 == 开头的即可。

==34110== Invalid write of size 4
==34110== at 0x100000F3F: f() (demo.cpp:5)
==34110== by 0x100000F63: main (demo.cpp:9)
==34110== Address 0x100012a08 is 0 bytes after a block of size 40 alloc'd
==34110== at 0x6DFB: malloc (in /usr/local/Cellar/valgrind/3.9.0/lib/valgrind/vgpreload_memcheck-amd64-darwin.so)
==34110== by 0x100000F36: f() (demo.cpp:4)
==34110== by 0x100000F63: main (demo.cpp:9)

很快我们就会看到这样一段话,这就是我们要找的错误了。第一行写的是错误的原因,Invalid write 无效的写,接下来的几行会告诉我们错误发生的具体位置。

==34110== 40 bytes in 1 blocks are definitely lost in loss record 32 of 76
==34110== at 0x6DFB: malloc (in /usr/local/Cellar/valgrind/3.9.0/lib/valgrind/vgpreload_memcheck-amd64-darwin.so)
==34110== by 0x100000F36: f() (demo.cpp:4)
==34110== by 0x100000F63: main (demo.cpp:9)

再往下看,我们就能看到内存泄漏的问题,可以看到第一行说definitely lost这就说明这一定是一个内存泄漏,必须要修改。

==34110== LEAK SUMMARY:
==34110== definitely lost: 40 bytes in 1 blocks
==34110== indirectly lost: 0 bytes in 0 blocks
==34110== possibly lost: 0 bytes in 0 blocks
==34110== still reachable: 0 bytes in 0 blocks
==34110== suppressed: 25,231 bytes in 377 blocks

最后会有一个内存泄漏检查的总结,其中
definitely lost 是一定会发生的内存泄漏是一定要改的
indirectly lost 是指间接的内存泄漏,一般情况都是有definitely lost所引起的,默认不显示具体信息
Possibly lost 这种错误一般也是内存泄漏,需要修改
Still reachable 是指程序结束之后这个指针还存在但是没有被释放,这种情况到底算不算内存泄漏是个比较有争议的问题,不过在valgrind里面这种情况不算是内存泄漏,默认也是不显示具体信息的,所以如果你想要看到的话在运行valgrind的时候记得加上参数–show-leak-kinds=all

好了知道错误之后我们就去源程序中进行调试,经过一番调试修改之后,我们再次运行valgrind,就可以得到如下结果:

==34289== LEAK SUMMARY:
==34289== definitely lost: 0 bytes in 0 blocks
==34289== indirectly lost: 0 bytes in 0 blocks
==34289== possibly lost: 0 bytes in 0 blocks
==34289== still reachable: 0 bytes in 0 blocks
==34289== suppressed: 25,231 bytes in 377 blocks
==34289==
==34289== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 148 from 49)

OK,That’s what I want。