Valgrind快速入门指南西安出国留学
翻译:何庆玮
联系:
原文:www.valgrind/docs/manual/quick-start.html#quick-start.prepare
2010-6-4
·1简介
Valgrind工具套件提供让程序更加高效与安全的调试与剖析工具。其中最受欢迎的是Memcheck,它可以探测到C/C++中常见的内存相关错误,而这些错误可能导致程序的崩溃或者一些不可预知的行为。
jnk以下的内容给出了使用Memcheck调试内存错误的一些简要信息。您可以查阅用户手册获取更多的关于Memcheck与其他调试工具的使用资料。
·2准备程序
为了使Memcheck调试信息包含具体的错误所在行号,请使用-g参数编译程序。如果可以接受较慢的程序运行速度,可以尝试使用-O0参数。而是用-O1参数可能会导致调试信息不够精准,虽然一般情况下使用Memcheck调试使用-O1参数编译的程序也可以得到不错的结果。不推荐使用-O2或更加优化的编译选项,因为偶尔会有报道说Memcheck在调试此类程序时会出现原本不存在的变量未初始化错误。
·3使用Memcheck调试程序
如果你通常使用如下的方式运行程序:
come upwarmyprog arg1arg2
那么在使用Valgrind调试程序时可以使用如下的命令:
valgrind--leak-check=yes myprog arg1arg2
atomic clockMemcheck被用作默认的调试工具,而--leak-check选项用于开启详细的内存泄露探测功能。在此调试模式下,你的程序运行速度会比通常情况下低(比如降低20到30倍于常速),并会消耗更多的内存。使用以上的调试命令,Memcheck会给出内存错误与内存泄露的信息。
·4Memcheck输出含义
以下是一个示例C程序a.c。此程序包含了一处内存错误和一处内存泄露的bug。
#include<stdlib.h>
void f(void)
{
int*x=malloc(10*sizeof(int));
x[10]=0;//bug1:堆内存溢出
}//bug2:内存泄露——没有释放x六级高频词汇
int main(void)
{
f();
return0;
}
对于堆内存溢出的bug,使用Memcheck探测出的错误消息大多如下:
==19182==Invalid write of size4
==19182==at0x804838F:f(example.c:6)
==19182==by0x80483AB:main(example.c:11)
dhc是什么
学汽车美容==19182==Address0x1BA45050is0bytes after a block of size40alloc'd
==19182==at0x1B8FF5CD:malloc(vg_replace_malloc.c:130)
==19182==by0x8048385:f(example.c:5)
==19182==by0x80483AB:main(example.c:11)
需要注意的是:
|每个错误都包含有大量的描述信息,应仔细阅读。
|19182是进程编号,通常不太重要。
|第一行的(“”)告诉你错误的类型,在本示例中语句x[10]=0;访问了不属于数组x的内存。
|第一行之下的内容是堆栈跟踪,它指示了问题发生的地方。堆栈跟踪可能给出大量的不易理解的信息,特别是在使用C++STL的时候。使用从下向上的阅读方式可以更好的理解这些信息。如果堆栈跟踪没有包含足够的信息,可以尝试使用--num-callers选项。
english resume
|代码地址(比如0x804838F)通常并不重要,但有时会对发现一些奇怪的bug起到关键作用。
|有些错误包含了与内存地址相关的第二部分信息。该部分显示程序第5行出现了写入数据到分配空间末尾以外内存的错误。应该按照报告错误的顺序解决问题,因为后面的错误可能是由前面的错误导致。否则会使Memcheck的调试过程变得复杂。
|内存泄露的信息如下:
==19182==40bytes in1blocks are definitely lost in loss record1of1
==19182==at0x1B8FF5CD:malloc(vg_replace_malloc.c:130)
==19182==by0x8048385:f(a.c:5)
==19182==by0x80483AB:main(a.c:11)
以上的堆栈跟踪信息告诉你内存泄露发生的位置。然而遗憾的是,Memcheck不能指示内存泄露的原因。(应忽略“vg_replace_malloc.c”,这是补充的细节信息。)
存在多种内存泄露情况,最常见的两种如下:
|“确定性丢失”:你的程序发生的明确的内存泄露,必须修复。
|“可能性丢失”:你的程序可能会因为一些非正常的指针操作造成内存丢失(比如将指针指向堆内存的中间)。
Memcheck也会报告使用未初始化变量的问题,通常使用如下信息:“Conditional jump or move depends on uninitialid value(s)”(增加或移动未初始化的变量)。而这样的信息很难确定错误的根本原因。可以尝试使用--track-origins=yes来获取额外信息。这会导致Memcheckd的运行速度变慢,但是却可以节约大量为弄清未初始化变量的来源而花费的时间。
如果你不理解错误信息的含义,请参阅Valgrind用户手册中Memcheck错误信息解释中的内容,该内容包含了Memcheck提供的所有错误信息的示例。
desc
·5注意事项
Memcheck并不完美,它有时会产生误报。值得高兴的是存在消除误报的机制(参考Valgrin用户手册中消除错误中的内容)。无论如何通常Memcheck会保证99%的正确率,但你还是要提放可能的误报。毕竟你不会忽略由编译器产生的警告信息。如果Memcheck报告
了在你不能修改的库中发生的错误,消除错误的机制就会派上用场。默认情况下Memcheck 抑制了大
量的上述类型的错误,但是你可能会遇到更多。
Memcheck并不能探测到你程序中存在所有错误。比如它不能探测出发生在静态存储区或堆栈上的溢出的数组读写操作错误。但是它可以探测到许多导致程序崩溃的错误。
尽力完善你的程序到Memcheck无法检测出任何错误的程度。一旦做到这一程度,当程序改变而产生信息的错误的时候,你会更容易的发现此错误。根据数年的Memcheck使用经验可以得出这样的结论:在一个庞大的工程中做到Memcheck检查无错是可能的。比如大部分的KDE,OpenOffice以及火狐都是Memcheck检查无错或几乎无错的。
·6更多信息
请参阅Valgrind FAQ和Valgrind用户手册,它们包含了更多的信息。需要注意一点:要使用Valgrind工具集中的其它工具可以使用--tool选项。
声明:笔者水平有限,如有错误,欢迎批评指正。