因为最近要测试一个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。