用C/C++开发其中最使人头疼的一个问题就是内存管理,有时候为了查找一个内存泄漏或者一个内存访问越界,须要要花上好几天时间,若是有一款工具可以帮助咱们作这件事情就行了,valgrind正好就是这样的一款工具。 linux
Valgrind是一款基于模拟linux下的程序调试器和剖析器的软件套件,能够运行于x86, amd64和ppc32架构上。valgrind包含一个核心,它提供一个虚拟的CPU运行程序,还有一系列的工具,它们完成调试,剖析和一些相似的任务。valgrind是高度模块化的,因此开发人员或者用户能够给它添加新的工具而不会损坏己有的结构。 多线程
valgrind的官方网址是:http://valgrind.org 架构
你能够在它的网站上下载到最新的valgrind,它是开放源码和免费的。 模块化
1、介绍 函数
valgrind包含几个标准的工具,它们是: 工具
一、memcheck 优化
memcheck探测程序中内存管理存在的问题。它检查全部对内存的读/写操做,并截取全部的malloc/new/free/delete调用。所以memcheck工具可以探测到如下问题: 网站
1)使用未初始化的内存 spa
2)读/写已经被释放的内存 线程
3)读/写内存越界
4)读/写不恰当的内存栈空间
5)内存泄漏
6)使用malloc/new/new[]和free/delete/delete[]不匹配。
二、cachegrind
cachegrind是一个cache剖析器。它模拟执行CPU中的L1, D1和L2 cache,所以它能很精确的指出代码中的cache未命中。若是你须要,它能够打印出cache未命中的次数,内存引用和发生cache未命中的每一行代码,每个函数,每个模块和整个程序的摘要。若是你要求更细致的信息,它能够打印出每一行机器码的未命中次数。在x86和amd64上,cachegrind经过CPUID自动探测机器的cache配置,因此在多数状况下它再也不须要更多的配置信息了。
三、helgrind
helgrind查找多线程程序中的竞争数据。helgrind查找内存地址,那些被多于一条线程访问的内存地址,可是没有使用一致的锁就会被查出。这表示这些地址在多线程间访问的时候没有进行同步,极可能会引发很难查找的时序问题。
2、valgrind对你的程序都作了些什么
valgrind被设计成非侵入式的,它直接工做于可执行文件上,所以在检查前不须要从新编译、链接和修改你的程序。要检查一个程序很简单,只须要执行下面的命令就能够了
valgrind --tool=tool_name program_name
好比咱们要对ls -l命令作内存检查,只须要执行下面的命令就能够了
valgrind --tool=memcheck ls -l
不论是使用哪一个工具,valgrind在开始以前总会先取得对你的程序的控制权,从可执行关联库里读取调试信息。而后在valgrind核心提供的虚拟CPU上运行程序,valgrind会根据选择的工具来处理代码,该工具会向代码中加入检测代码,并把这些代码做为最终代码返回给valgrind核心,最后valgrind核心运行这些代码。
若是要检查内存泄漏,只须要增长--leak-check=yes就能够了,命令以下
valgrind --tool=memcheck --leak-check=yes ls -l
不一样工具间加入的代码变化很是的大。在每一个做用域的末尾,memcheck加入代码检查每一片内存的访问和进行值计算,代码大小至少增长12倍,运行速度要比平时慢25到50倍。
valgrind模拟程序中的每一条指令执行,所以,检查工具和剖析工具不只仅是对你的应用程序,还有对共享库,GNU C库,X的客户端库都起做用。
3、如今开始
首先,在编译程序的时候打开调试模式(gcc编译器的-g选项)。若是没有调试信息,即便最好的valgrind工具也将中可以猜想特定的代码是属于哪个函数。打开调试选项进行编译后再用valgrind检查,valgrind将会给你的个详细的报告,好比哪一行代码出现了内存泄漏。
当检查的是C++程序的时候,还应该考虑另外一个选项 -fno-inline。它使得函数调用链很清晰,这样能够减小你在浏览大型C++程序时的混乱。好比在使用这个选项的时候,用memcheck检查openoffice就很容易。固然,你可能不会作这项工做,可是使用这一选项使得valgrind生成更精确的错误报告和减小混乱。
一些编译优化选项(好比-O2或者更高的优化选项),可能会使得memcheck提交错误的未初始化报告,所以,为了使得valgrind的报告更精确,在编译的时候最好不要使用优化选项。
若是程序是经过脚本启动的,能够修改脚本里启动程序的代码,或者使用--trace-children=yes选项来运行脚本。
下面是用memcheck检查ls -l命令的输出报告,在终端下执行下面的命令
valgrind --tool=memcheck ls -l
程序会打印出ls -l命令的结果,最后是valgrind的检查报告以下:
==4187==
==4187== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 19 from 2)
==4187== malloc/free: in use at exit: 15,154 bytes in 105 blocks.
==4187== malloc/free: 310 allocs, 205 frees, 60,093 bytes allocated.
==4187== For counts of detected errors, rerun with: -v
==4187== searching for pointers to 105 not-freed blocks.
==4187== checked 145,292 bytes.
==4187==
==4187== LEAK SUMMARY:
==4187== definitely lost: 0 bytes in 0 blocks.
==4187== possibly lost: 0 bytes in 0 blocks.
==4187== still reachable: 15,154 bytes in 105 blocks.
==4187== suppressed: 0 bytes in 0 blocks.
==4187== Reachable blocks (those to which a pointer was found) are not shown.
==4187== To see them, rerun with: --show-reachable=yes
这里的“4187”指的是执行ls -l的进程ID,这有利于区别不一样进程的报告。memcheck会给出报告,分配置和释放了多少内存,有多少内存泄漏了,还有多少内存的访问是可达的,检查了多少字节的内存。
下面举两个用valgrind作内存检查的例子
例子一 (test.c):
#include <string.h> int main(int argc, char *argv[]) { char *ptr; ptr = (char*) malloc(10); strcpy(ptr, "01234567890"); return 0; } |
编译程序
gcc -g -o test test.c
用valgrind执行命令
valgrind --tool=memcheck --leak-check=yes ./test
报告以下
==4270== Memcheck, a memory error detector.
==4270== Copyright (C) 2002-2006, and GNU GPL'd, by Julian Seward et al.
==4270== Using LibVEX rev 1606, a library for dynamic binary translation.
==4270== Copyright (C) 2004-2006, and GNU GPL'd, by OpenWorks LLP.
==4270== Using valgrind-3.2.0, a dynamic binary instrumentation framework.
==4270== Copyright (C) 2000-2006, and GNU GPL'd, by Julian Seward et al.
==4270== For more details, rerun with: -v
==4270==
==4270== Invalid write of size 1
==4270== at 0x4006190: strcpy (mc_replace_strmem.c:271)
==4270== by 0x80483DB: main (test.c:8)
==4270== Address 0x4023032 is 0 bytes after a block of size 10 alloc'd
==4270== at 0x40044F6: malloc (vg_replace_malloc.c:149)
==4270== by 0x80483C5: main (test.c:7)
==4270==
==4270== Invalid write of size 1
==4270== at 0x400619C: strcpy (mc_replace_strmem.c:271)
==4270== by 0x80483DB: main (test.c:8)
==4270== Address 0x4023033 is 1 bytes after a block of size 10 alloc'd
==4270== at 0x40044F6: malloc (vg_replace_malloc.c:149)
==4270== by 0x80483C5: main (test.c:7)
==4270==
==4270== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 12 from 1)
==4270== malloc/free: in use at exit: 10 bytes in 1 blocks.
==4270== malloc/free: 1 allocs, 0 frees, 10 bytes allocated.
==4270== For counts of detected errors, rerun with: -v
==4270== searching for pointers to 1 not-freed blocks.
==4270== checked 51,496 bytes.
==4270==
==4270==
==4270== 10 bytes in 1 blocks are definitely lost in loss record 1 of 1
==4270== at 0x40044F6: malloc (vg_replace_malloc.c:149)
==4270== by 0x80483C5: main (test.c:7)
==4270==
==4270== LEAK SUMMARY:
==4270== definitely lost: 10 bytes in 1 blocks.
==4270== possibly lost: 0 bytes in 0 blocks.
==4270== still reachable: 0 bytes in 0 blocks.
==4270== suppressed: 0 bytes in 0 blocks.
==4270== Reachable blocks (those to which a pointer was found) are not shown.
==4270== To see them, rerun with: --show-reachable=yes
从这份报告能够看出,进程号是4270,test.c的第8行写内存越界了,引发写内存越界的是strcpy函数,
第7行泄漏了10个字节的内存,引发内存泄漏的是malloc函数。
例子二(test2.c)
#include <stdio.h> int foo(int x) { if (x < 0) { printf("%d ", x); } return 0; } int main(int argc, char *argv[]) { int x; foo(x); return 0; } |
编译程序
gcc -g -o test2 test2.c
用valgrind作内存检查
valgrind --tool=memcheck ./test2
输出报告以下
==4285== Memcheck, a memory error detector.
==4285== Copyright (C) 2002-2006, and GNU GPL'd, by Julian Seward et al.
==4285== Using LibVEX rev 1606, a library for dynamic binary translation.
==4285== Copyright (C) 2004-2006, and GNU GPL'd, by OpenWorks LLP.
==4285== Using valgrind-3.2.0, a dynamic binary instrumentation framework.
==4285== Copyright (C) 2000-2006, and GNU GPL'd, by Julian Seward et al.
==4285== For more details, rerun with: -v
==4285==
==4285== Conditional jump or move depends on uninitialised value(s)
==4285== at 0x8048372: foo (test2.c:5)
==4285== by 0x80483B4: main (test2.c:16)
==4285==p p
==4285== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 12 from 1)
==4285== malloc/free: in use at exit: 0 bytes in 0 blocks.
==4285== malloc/free: 0 allocs, 0 frees, 0 bytes allocated.
==4285== For counts of detected errors, rerun with: -v
==4285== All heap blocks were freed -- no leaks are possible.
从这份报告能够看出进程PID是4285,test2.c文件的第16行调用了foo函数,在test2.c文件的第5行foo函数使用了一个未初始化的变量。
valgrind还有不少使用选项,具体能够查看valgrind的man手册页和valgrind官方网站的在线文档。