1、valgrind检测原理
valgrind 是一个提供了一些 debug 和优化的工具的工具箱,可以使得你的程序减少内存泄漏或者错误访问。valgrind 默认使用 memcheck 去检查内存问题。memcheck 检测内存问题的原理如下图所示:
Memcheck 能够检测出内存问题,关键在于其建立了两个全局表。
valid-value map:对于进程的整个地址空间中的每一个字节(byte),都有与之对应的 8 个 bits;对于 CPU 的每个寄存器,也有一个与之对应的 bit 向量。这些 bits 负责记录该字节或者寄存器值是否具有有效的、已初始化的值。
valid-address map:对于进程整个地址空间中的每一个字节(byte),还有与之对应的 1 个 bit,负责记录该地址是否能够被读写。在两个全局表的基础上,以如下方式进行检测:
当要读写内存中某个字节时,首先检查 valid-address map 中这个字节对应的 A bit。
如果该A bit显示该位置是无效位置,memcheck 则报告读写错误。内核(core)类似于一个虚拟的 CPU 环境,这样当内存中的某个字节被加载到真实的 CPU 中时,该字节对应的 V bit (在 valid-value map 中) 也被加载到虚拟的 CPU 环境中。一旦寄存器中的值,被用来产生内存地址,或者该值能够影响程序输出,则 memcheck 会检查对应的 V bits,如果该值尚未初始化,则会报告使用未初始化内存错误。
不过valgrind也不是万能的,对于栈上的内存空间操作就无法检测到。
2、命令选项
基本命令:valgrind --leak-check=yes ./a.out arg1 arg2
为了能够定位到源代码的行,建议编译时加上-g选项,并选择O0优化
3、使用示例
示例代码:
#includeintmain() { int*x=(int*)malloc(10*sizeof(int)); x[10]=1;//问题1,越界了 return0;//问题2,没有释放内存 }
执行valgrind检测后的结果:
barret@Barret-PC:~$valgrind--leak-check=yes./a.out ==393==Memcheck,amemoryerrordetector ==393==Copyright(C)2002-2017,andGNUGPL'd,byJulianSewardetal. ==393==UsingValgrind-3.15.0andLibVEX;rerunwith-hforcopyrightinfo ==393==Command:./a.out ==393== ==393==Invalidwriteofsize4 ==393==at0x10916B:main(a.cpp:6) ==393==Address0x4a47068is0bytesafterablockofsize40alloc'd ==393==at0x483B7F3:malloc(in/usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so) ==393==by0x10915E:main(a.cpp:5) ==393== ==393== ==393==HEAPSUMMARY: ==393==inuseatexit:40bytesin1blocks ==393==totalheapusage:1allocs,0frees,40bytesallocated ==393== ==393==40bytesin1blocksaredefinitelylostinlossrecord1of1 ==393==at0x483B7F3:malloc(in/usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so) ==393==by0x10915E:main(a.cpp:5) ==393== ==393==LEAKSUMMARY: ==393==definitelylost:40bytesin1blocks ==393==indirectlylost:0bytesin0blocks ==393==possiblylost:0bytesin0blocks ==393==stillreachable:0bytesin0blocks ==393==suppressed:0bytesin0blocks ==393== ==393==Forlistsofdetectedandsuppressederrors,rerunwith:-s ==393==ERRORSUMMARY:2errorsfrom2contexts(suppressed:0from0)
结果解析如下:
==393==:执行程序的进程ID
Invalid write of size 4:表示发现一个错误,这里显示源代码第6行有错误,这里很明显是越界了,所以显示invalid write错误
40 bytes in 1 blocks are definitely lost in loss record 1 of 1:内存泄露错误,泄漏的大小是10* sizeof(int)40byte。
LEAK summary也会显示内存泄漏的情况
4、分析常见内存问题
4.1、写入非法内存地址
上面的例子已经展示了这种情况,访问分配的内存区域之外的空间,valgrind会上报如下的错误:
Invalid
write of size x
后跟调用栈信息
4.2、读取非法内存地址
和上一个情况类似,不同 的是读取而不是写入,错误信息如下:
Invalid
read of size x
后跟调用栈信息
4.3、读取未初始化内存区域
#includeintmain() { int*x=(int*)malloc(10*sizeof(int)); inta=x[1]+1;//不初始化就使用内存的值 free(x); returna; }
valgrind显示如下错误:
==427==Syscallparamexit_group(status)**containsuninitialisedbyte(s)** ==427==at0x4938136:Exit(exit.c:31) ==427==by0x489BB41:__run_exit_handlers(exit.c:132) ==427==by0x489BBDF:exit(exit.c:139) ==427==by0x48790B9:(belowmain)(libc-start.c:342)
4.4、内存双重释放
示例:
#includeintmain() { int*x=(int*)malloc(10*sizeof(int)); free(x);//free两次 free(x); return0; }
valgrind显示如下错误,显示两次free的位置:
==436==Invalidfree()/delete/delete[]/realloc() ==436==**at0x483CA3F:free(in/usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so) ==436==by0x10919A:main(a.cpp:7) ==436==Address0x4a47040is0bytesinsideablockofsize40free'd ==436==at0x483CA3F:free(in/usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so) ==436==by0x10918E:main(a.cpp:6)** ==436==Blockwasalloc'dat ==436==at0x483B7F3:malloc(in/usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so) ==436==by0x10917E:main(a.cpp:5)
-
内存
+关注
关注
8文章
3008浏览量
73918 -
程序
+关注
关注
116文章
3779浏览量
80894 -
Valgrind
+关注
关注
0文章
9浏览量
6797
原文标题:Linux内存泄漏调试利器-valgrind
文章出处:【微信号:嵌入式应用研究院,微信公众号:嵌入式应用研究院】欢迎添加关注!文章转载请注明出处。
发布评论请先 登录
相关推荐
评论