您的位置:首页 > 其它

Valgrind内存泄漏和内存越界访问检查工具

2016-09-24 12:59 483 查看
在写C/C++程序时,要小心内存泄漏,内存越界访问,但最粗心的也就是这一块;在程序运行过程中,最担心的也就是突然core掉,或程序占用完内存。此时要么DBG产生的core文件,要么是查看日志再对照源代码,假如此时你的源代码修改过。那就是噩梦了。

Valgrind是一个linux平台的内存调试工具。它允许你在Valgrind自己的环境中运行你的程序,监视内存使用,例如:调用malloc和free(或者是C++中的new和delete)。如果使用未初始化的内存,数组访问越界或者忘记释放指针,Valgrind就能够检测出来。

使用valgrind之前 ,当然是要拥有它了。

获得valgrind

如果你的linux系统上还未安装valgrind,你可以用鼠标戳这里穿越到valgrind下载页面

获得安装包时,使用以下命令解压(下面的xyz是版本号):

tar -jxvf valgrind-xyz.tar.bz2
或下面两行命令
bzip2 -d vavlgrind-xyz.bar.bz2
tar -xf valgrind-xyz.tar


此时会创建一个叫valgrind-xyz的目录。切换到该目录,然后执行下列命令:

./configure --prefix=/usr/local/valgrind
make
make install


–prefix指定valgrind的安装目录

使用make和make install时注意当前的权限

现在,valgrind就安装在你的系统里面了。你可以使用以下命令查看:

which valgrind
/usr/local/bin/valgrind
或
valgrind --version
valgrind-3.11.0


使用valgrind查看内存泄漏

内存泄漏是所有bugs最难检测到,除非你耗尽所有的内存,否则它不会导致任何显式的错误此,时你调用malloc突然会失败。事实上当使用像C或者C++这类没有垃圾回收机制的语言,几乎一半的时间都浪费在处理正确的释放内存上面。如果你的程序运行的时间足够长,那么查找这个分支上的代码,甚至仅仅一个错误,也会花费很大的代价。

幸运的是你可以使用valgrind,仅仅运行一下该程序,将会获得一个当前的错误列表。

下面是一个例子example.c。

#include <stdlib.h>
int main()
{
char *x = malloc(100); /* or,in c++,"char *x=new[100] */
return 0;
}


gcc -o example -g example.c
% valgrind --tool=memcheck --leak-check=yes example

==9626== 100 bytes in 1 blocks are definitely lost in loss record 1 of 1
==9626==    at 0x4C2911D: malloc (vg_replace_malloc.c:299)
==9626==    by 0x40054E: main (example.c:4)


从上面列出的信息中可以看到在main函数的第4行调用malloc有内存泄漏

非法指针使用

valgrind能够发现使用非法的堆内存。使用malloc或者new操作指定一个数组,然后试着去访问数组后面的内存。

char x* = malloc(10);
x[10] = 'a';


下面是示例example2.c

#include <stdlib.h>
int main()
{
char *x=malloc(10);
x[10]='a';
return 0;
}


现在使用valgrind

valgrind --tool=memcheck --leak-check=yes exmple2
==9728== Invalid write of size 1
==9728==    at 0x40055B: main (example2.c:5)
==9728==  Address 0x51dd04a is 0 bytes after a block of size 10 alloc'd
==9728==    at 0x4C2911D: malloc (vg_replace_malloc.c:299)
==9728==    by 0x40054E: main (example2.c:4)


下面来看一下未初始化变量的检测

#include<stdio.h>
int main()
{
int x;
if( 0 == x )
{
printf("x is zero");
}
return 0;
}


使用valgrind检测之后,会有如下的结果输出:

==9798== Conditional jump or move depends on uninitialised value(s)
==9798==    at 0x400549: main (example3.c:5)


valgrind甚至智能到足够检测到一个变量初指定一个未初始化的变量,这个变量一直是未初始化的状态,如下代码example4.c所示:

#include <stdio.h>
int foo(int x)
{
if( x < 10 )
{
printf("x is less than 10\n");
}
return 0;
}
int main()
{
int y;
foo(y);
return 0;
}


valgrind检测到example4有如下的告警:

==10050== Conditional jump or move depends on uninitialised value(s)
==10050==    at 0x40054C: foo (example4.c:4)
==10050==    by 0x400570: main (example4.c:14)


什么是valgrind不能发现的?

valgrind不能检测静态数组(在栈上分配的数组)的越界,所发如果在你的代码中

声明一个数组:

int main()
{
char x[10];
x[11] = 'a';
return 0;
}


valgrind不会给你一个告警,一个测试目的地解决方法是修改你的静态数组为在堆上动态分配,这时你会得到内存边界检查,这样会导致一堆未释放的内存。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息