使用valgrind工具调试内存泄漏


作者:lingyun 来源:凌云物网智科实验室 时间:2014-01-28

valgrind [valgrind-options] [your-program] [your-program-options]

valgrind     [valgrind选项]     [自己的程序]          [自己程序的参数]

使用示例:

valgrind –track-fds=yes –leak-check=full –leak-resolution=high –track-origins=yes -v ./hello

valgrind的底层模拟了一个核心,即一个软件模拟的CPU,被调试的程序就是运行在这个假核心上,此外还包含一系列调试工具。它的工具运行依赖于底层的核心,由于是模块化架构,工具可单独开发,只要与核心的版本匹配即可。它的默认工具是memcheck,每个工具可能有自己的命令选项,通过–tool=<toolname>来指定运行的工具。

所有工具都可用的选项

-h –help:显示核心和所选工具的所有选项(-h或是–help),若是-h –help,则等效为–help-debug,即同时显示调试选项(一般为Valgrind的开发者所用)。

–version:先是核心版本。

-q, –quiet:安静的运行,只打印错误信息(被调试的程序错误信息)。

-v, –verbose:给的信息就多了,与-q相反。给出被调试程序的全面信息,如加载了哪些共享库,用了哪些suppressions?执行进度,警告信息等。

–trace-children=<yes|no>:如果是yes,被调程序若用exec开启了一个子进程,那valgrind将会追踪此子进程的执行情况。默认是no,但无论如何,valgrind都还是追踪fork产生的子进程。

–trace-children-skip=patt1,patt2…:在上面选项设为yes后,这个选项则标识了哪些子进程是不要被追踪的,这些子进程(名字)由patt1,patt2…来决定,pattn可包含”?””*”等通配符。注意,valgrind将停止追踪pattn所指进程下可能产生的所有子进程。

–trace-children-skip-by-arg=patt1,patt2,…:与–trace-childrn-skip选项的不同之处是,跳过的子进程是由给子进程的参数patt1,patt2…来决定,而非程序名字。

–child-silent-after-fork=<yes|no>:若是yes,则不显示由fork调用产生的子进程产生的任何调试或log信息。当调试信息以XML格式输出时(–xml=yes),强烈建议开启此选项。默认是no。

–vgdb=<no|yes|full>:若为yes或full,valgrind允许在其上运行的程序,用GDB去调试它(开启gdbsever)。默认是yes。

–vgdb-error=<number>:在开启了gdbsever后,有用。报错工具在等待有number个错误报出后,会冻结程序并等你将它连上GDB。因此,当number=0时,在你的程序运行前,gdbserver就开始运行了。典型应用场景是,在运行前插入GDB断点,还有使用那些不报错的工具的情况,如Massif。默认是999999999。

–trace-fds=<yes|no>:若是yes,在程序退出时,将打印一系列的程序打开的文件描述符的信息。包括文件是在哪打开的,文件名字或socket细节等。默认是no。

–time-stamp=<yes|no>:若 yes,每条信息前将挂个时间信息,指示自程序开始,过去的时间量。

–log-fd=<number>:将vaolgrind的输出信息输向由number这个文件描述符指定的文件,默认是2,即stderr。注意,这可能与用户自己向stderr输出的东西相互交织。

–log-file=<filename>:将信息输向右filename指定的文件。若filename是空,则会引发终止。filename中可有三种格式信息;1,%p将被替换为当前进程的ID。当—trace-children=yes,而没用%p时,所有进程的信息都输向同一个文件,会比较混乱,信息也可能不全,最好文件名中包含%p。2,%q{FOO}被环境变量FOO的值代替,若FOO的内容奇怪的话也可能引发异常。一般不用这种格式,除了极少情况,如基于MPI(一种并行程序开发库)的程序。若用了此种格式,FOO不能为空,否则也引发异常。一些shell里面,”{””}”可能需要反斜杠转义。3,%%被代替为%,%不能后接任何其他字符,否则会引发异常。

–log-socket=<ip-address:port-number>:将信息输向指定的IP地址。若省了port-number,则默认用1500端口号。若这个IP地址无法接受信息,信息将被写会到stderr。

与报错相关的选项

这些选项适用于所有能报错的工具,如memcheck,而cachegrind就用不了。

–xml=<yes|no>:若为yes,错误信息将以XML格式形式输出,而非平面文档。不重要的信息(非错误信息)被打印在平面文档中。XML输出目标由–xml-fd或–xml-file或—xml-socket指定,而平面文档信息输出目标则由前面的—log-fd或—log-file或—log-socket指定。输出格式由docs/internals/xml-output-protocol4.txt设定。

–xml-fd=<number>:将XML信息输出到由文件描述符number指定的文件中,必须要–xml=yes。

–xml-file=<filename>:与—log-file类似。也必须要—xml=yes。

–xml-socket=<ip-address:port-number>:与—log-socket类似,也必须要—xml=yes。

–xml-user-comment-<string>:在输出的XML文件开头,加的注释信息,没有—xml=yes的话,将被忽略。

–demangle=<yes|no>:这个选项开启的话,会试图还原目标代码中的C++符号名,使其与源码中的相关符号名字尽量一致。默认是yes。

–num-callers=<number>:定义了在堆栈追踪过程中显示的最大嵌套调用数。注意,valgrind只显示四层嵌套调用的错误信息,故这个选项不影响最终报道的错误信息量。Number最大值是50,默认值是12。

–error-limit=<yes|no>:若为yes,则当报道出的错误总数超过10000000或有1000个不同类型的,则停止报错。这么多错误的程序也就没必要再调试了,默认是yes。

–error-exitcode=<number>:设置在发现任何错误信息时的valgrind的返回码。默认是0,这样返回码就是被调程序的返回码。若设为非0值,则此值将代替默认的返回码。

–show-below-main=<yes|no>:默认是no,追踪堆栈错误时,不显示在那些在main函数下一层那些函数调用的错误信息。

–fullpath-after=<string>:string的默认 值是“don’t show source paths”,即在堆栈追踪过程中只显示文件名,而不显示源文件的完全路径。对于大的项目,众多源文件分布在不同路径下,这个默认行为就不方便了。设置了string后,将会显示每个源文件的路径,但若路径中含有string的内容,则路径中与string的重合部分直至路径开头(根目录)将被省略。如一个源文件的全路径为/home/janedoe/ blah/src/foo/bar/xyzzy.c,选项设置为–fullpath-after=/home/janedoe/blash/src/,则显示的文件名将是foo/bar/xyzzy.c。由于string不需要加路径前缀,故–fullpath-after=/blash/src/,效果是一样的。若要显示全路径的话,不要为string赋值即可,即–fullpath-after=。这个选项还可以多次使用,以它们在命令行出现的次序为先后顺序,依次按照上面的规则对路径进行截断。

–gen-suppressions=<yes|no|all>:若选择yes,则每显示一条error,valgrind就暂停,并打印一行:—-Print suppression ?—[Return/N/n?Y/y/C/c]—(y=yes,n=no,c=cancle)这条提示信息与下面的–db-attach选项相同,选y,则打印针对这个error的suppressions。若该选项为all,则打印每个error的suppression,不在询问了。Also, the suppression name is given as <insert a suppression name here>; the name doesn’t really matter, it’s only used with the -v option which prints out all used suppression records.

–db-attach=<yes|no>:若选yes,则每显示一条error,valgrind就暂停,并打印一行:—-Attach to debugger ?—[RegurnN/n/Y/y/C/c]—。若选y,则在此处启动调试器,调试完了要退出调试器,valgrind才可继续。若你用的是GDB,则选项–vgdb=yes或ful会使得调试器功能更强(它启动了valgrind内部的gdbsever,几乎模拟了 GDB的全部功能)。

–db-command=<command>:开启–db-attach选项时,实际用的命令,默认是”gdb -nw %f %p”,其中%f是被调试的程序名,%p是被调进程的ID,默认的调试器是valgrind安装时它发现的,一般是/usr/bin/gdb。command应该放在双引号内。

–input-fd=<number>:当–db-attach=yes或–gen-suppressions=yes时,valgrind在发现错误时会等待键盘输入即便进行下一步操作,即number默认是0(stdin),通过修改number,可以使得valgrind读取指定文件来执行下一步操作,在关闭了stdin时,这个选项有用。

–dsymutil=no|yes:这个选项只在MacOS上跑valgrind才有用。

–max-stackframe=<number>:该选项规定了被调程序能使用的最大栈帧空间。默认是2000000。这个选项一般在valgrind的调试输出建议你用时,再用。其实若被valgrind建议了,说明你的程序有问题,最好别在栈上分配太大的数据结构,大的数据最好在堆上分配。

–main-stacksize=<number>:规定了主线程的栈大小。默认情况用ulimit值,一般是16MB或低一点。一般用8~16M能满足绝大部分应用程序的需求。Linux上可最大申请2GB。若valgrid无法分配这么多空间,便会终止。这个选项只影响initial thread,对其他线程栈无影响。 You will have to work out the –main-stacksize value for yourself (usually, if your applications segfaults). But Valgrind will tell you the needed –max-stackframe size, if necessary.

与malloc()函数有关的选项:

–alignment=<number>:默认是8或16,取决于系统平台。这个选项对那些有自己版本的malloc的工具有用,如Memcheck和Massif,它设定了对分配地址的对齐性要求。number必须大于等于默认值,小于4096,必须是2的几次方。

valgrind–memcheck工具命令选项

–leak-check=<no|summary|yes|full>:如果设为yes或full,在被调程序结束后,valgrind会详细叙述每一个内存泄露情况,默认是summary,只报道发生了几次内存泄露。

–show-possibly-lost=<yes|no>:默认是yes。若设为no,则内存泄露检查将不显示那些“possibly lost”块。

–leak-resolution=<low|med|high>:这个选项设定内存检查工具在检测出多个内存泄露时,如何将这些内存泄露归结为同一个泄露(合并那些由相同原因引起的)。设为low时,试图合并前两个泄露情况,设为med,则是前四个,默认是high,试图合并所有的泄露情况。这个选项不影响memcheck找泄露的能力,只是影响它的检测结果显示。

–show-reachable=<yes|no>:默认情况是no,即内存泄露检测工具只显示”definitely lost”和“possibly lost”块,若启动的话(yes),还会显示“reachable”和“indirectly lost”块,也就是说,除了被suppressed的那些,可能泄露的块都会被显示出来,其实这个选项的名字改为–show-all更合适。

–undef-value-errors=<yes|no>:默认是yes,即memcheck会报道引用未定义错误(uses of undefined value errors),这对检测速度有点影响。

–track-origins=<yes|no>:这个选项控制memcheck是否追踪对未初始化值引用错误的根源。默认情况是不追踪,即它会告诉你程序引用了一个未初始化的值,但不知这个未初始化的值来自何处。若设为yes,memcheck将会追踪到未初始化的源。这个源可能出现在如下四种情况:堆上的、栈上的、clent requist、其他的。对于来自堆块上的未初始化值,memcheck会显示这个块是在哪分配的。对于栈上的未初始化值,memcheck会告诉你是哪个函数干的。这个选项的开销是相当大的。该选项不能与–undef-value-errors=no连用。

–partial-loads-ok=<yes|no>:这个选项决定memcheck如何处理word-sized和word-aligned数据(来自addresses)的加载情况,addresses处的一些字节块的地址是可重分配地址的,其余的不可。若设为yes,这种加载不会产生任何错误,当从非法地址处加载字节时会被标记为uninitialised,从合法地址加载的则按正常方式处理。默认是no,即将从部分无效的地址处的加载与从完全无效地址处的加载作同等处理,非法地址错误会被报道出来,相应的字节块被标记为initialised。其实这样的代码是不符ISO C/C++标准的,它应该被视为broken,不管如何,应该修正这样的代码,这个选项应该被作为最后的手段。

–freelist-vol=<number>:当客户程序用free或delete释放一个内存块时,这个内存块不会立即可用于再分配,它只会被放在一个freed blocks的队列中(freelist)并被标记为不可访问,这是为了尽可能延迟被释放的块再次被循环利用的(时间?)点,这样有利于探测到在一段很重要的时间后,客户程序又对被释放的块进行访问的错误。这个选项规定了队列所占的字节块大小,默认是20MB。增大这个选项的会增大memcheck的内存开销,但查错的能力也会提升。

–freelist-big-blocks=<number>:当从freelist队列中取可用内存块用于再分配时,memcheck将会从那些比number大的内存块中按优先级取出一个块出来用。这个选项就防止了freelist中那些小的内存块的频繁调用,这个选项提高了 查到针对小内存块的野指针错误的几率。若这个选项设为0,则所有的块将按先进先出的原则用于再分配。默认是1M。

–workaround-gcc296-bugs=<yes|no>:若开启这个选项,则当对栈顶指针下不远处进行读写时不会报错(gcc2.96的bug),这个不远距离默认是256B,默认是no。尽量不要开启这个选项,因为它真有可能造成错误而又不易被察觉,解决方法是用最新的GCC,它会修正这个错误。在老一点的GCC版本上,可能要用到这个选项。

–ignore-ranges=0xPP-0xQQ[,0xRR-0xSS]:这些区间之间的地址,在memcheck的寻址检查时将被省略,可以有多个地址区间,逗号隔开。(字母要被数字代替)

–malloc-fill=<hexnumber>:对用malloc和new分配出的内存块,用hexnumber对其进行初始化填充,但calloc分配的则不用。这个选项可能对那些不易察觉的memory corruption问题有用(就是你分配了大量的内存,都被hexnumber填充的话,说明你也没用这个内存块)。被分配的内存块仍被标记为undefined,它只影响里面的内容。

–free-fill=<hexnumber>:当用free和new释放一个内存块是,用hexnumber对内存块进行填充。它的好处与–malloc-fill的相同,被填充的内存仍不能被访问,它只影响它里面的内容。

在线咨询
微信号
13554373241
联系方式
135-5437-3241
邮箱
guowenxue@aliyun.com
返回顶部