您的位置:首页 > 运维架构 > Linux

在linux中使用valgrind检测内存情况

2015-03-20 14:47 239 查看
Valgrind是一款用于内存调试、内存泄漏检测以及性能分析的软件开发工具。

今天经同事介绍,发现了有这么一款工具,可以在linux中检测程序中存在的内存泄露情况。

使用方法: valgrind -v --tool=memcheck --leak-check=full ./processname

之后,就会运行程序,然后Valgrind就会在可能或者肯定有内存操作问题的地方输出错误提示。

下面有关一些Valgrind的一些错误提示及提示所表明的错误操作情况的简单举例。

原文地址:/article/4675558.html

例1.使用未初始化的内存

代码如下

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

Valgrind提示如下
==14222== Conditional jump or move depends on uninitialised value(s)
==14222== at 0x400484: main (sample2.c:6)
X is zero==14222==
==14222== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 5 from 1)
==14222== malloc/free: in use at exit: 0 bytes in 0 blocks.
==14222== malloc/free: 0 allocs, 0 frees, 0 bytes allocated.
==14222== For counts of detected errors, rerun with: -v
==14222== All heap blocks were freed -- no leaks are possible.


  

例2.内存读写越界

代码如下

#include <stdlib.h>
#include <stdio.h>
int main(int argc,char *argv[])
{
int len=5;
int i;
int *pt=(int*)malloc(len*sizeof(int));
int *p=pt;
for(i=0;i<len;i++)
{p++;}
*p=5;
printf(“%d”,*p);
return;
}
Valgrind提示如下
==23045== Invalid write of size 4
==23045== at 0x40050A: main (sample2.c:11)
==23045== Address 0x4C2E044 is 0 bytes after a block of size 20 alloc'd
==23045== at 0x4A05809: malloc (vg_replace_malloc.c:149)
==23045== by 0x4004DF: main (sample2.c:7)
==23045==
==23045== Invalid read of size 4
==23045== at 0x400514: main (sample2.c:12)
==23045== Address 0x4C2E044 is 0 bytes after a block of size 20 alloc'd
==23045== at 0x4A05809: malloc (vg_replace_malloc.c:149)
==23045== by 0x4004DF: main (sample2.c:7)
5==23045==
==23045== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 5 from 1)
==23045== malloc/free: in use at exit: 20 bytes in 1 blocks.
==23045== malloc/free: 1 allocs, 0 frees, 20 bytes allocated.
==23045== For counts of detected errors, rerun with: -v
==23045== searching for pointers to 1 not-freed blocks.
==23045== checked 66,584 bytes.
==23045==
==23045== LEAK SUMMARY:
==23045== definitely lost: 20 bytes in 1 blocks.
==23045== possibly lost: 0 bytes in 0 blocks.
==23045== still reachable: 0 bytes in 0 blocks.
==23045== suppressed: 0 bytes in 0 blocks.
==23045== Use --leak-check=full to see details of leaked memory.


  

例3.src和dst内存覆盖

代码如下

#include <stdlib.h>

#include <stdio.h>

#include <string.h>

int main(int argc,char *argv[])

{ char x[50];

int i;

for(i=0;i<50;i++)

{x[i]=i;}

strncpy(x+20,x,20); //Good

strncpy(x+20,x,21); //Overlap

x[39]=’\0’;

strcpy(x,x+20); //Good

x[39]=40;

x[40]=’\0’;

strcpy(x,x+20); //Overlap

return 0;

}

Valgrind提示如下

==24139== Source and destination overlap in strncpy(0x7FEFFFC09, 0x7FEFFFBF5, 21)

==24139== at 0x4A0724F: strncpy (mc_replace_strmem.c:116)

==24139== by 0x400527: main (sample3.c:10)

==24139==

==24139== Source and destination overlap in strcpy(0x7FEFFFBE0, 0x7FEFFFBF4)

==24139== at 0x4A06E47: strcpy (mc_replace_strmem.c:106)

==24139== by 0x400555: main (sample3.c:15)

==24139==

==24139== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 5 from 1)

==24139== malloc/free: in use at exit: 0 bytes in 0 blocks.

==24139== malloc/free: 0 allocs, 0 frees, 0 bytes allocated.

==24139== For counts of detected errors, rerun with: -v

==24139== All heap blocks were freed -- no leaks are possible.

例4.动态内存管理错误

常见的内存分配方式分三种:静态存储,栈上分配,堆上分配。全局变量属于静态存储,它们是在编译时就被分配了存储空间,函数内的局部变量属于栈上分配,而最灵活的内存使用方式当属堆上分配,也叫做内存动态分配了。常用的内存动态分配函数包括:malloc, alloc, realloc, new等,动态释放函数包括free, delete。

一旦成功申请了动态内存,我们就需要自己对其进行内存管理,而这又是最容易犯错误的。常见的内存动态管理错误包括:

l 申请和释放不一致

由于 C++ 兼容 C,而 C 与 C++ 的内存申请和释放函数是不同的,因此在 C++ 程序中,就有两套动态内存管理函数。一条不变的规则就是采用 C 方式申请的内存就用 C 方式释放;用 C++ 方式申请的内存,用 C++ 方式释放。也就是用 malloc/alloc/realloc 方式申请的内存,用 free 释放;用 new 方式申请的内存用 delete 释放。在上述程序中,用 malloc 方式申请了内存却用 delete 来释放,虽然这在很多情况下不会有问题,但这绝对是潜在的问题。

l 申请和释放不匹配

申请了多少内存,在使用完成后就要释放多少。如果没有释放,或者少释放了就是内存泄露;多释放了也会产生问题。上述程序中,指针p和pt指向的是同一块内存,却被先后释放两次。

l 释放后仍然读写

本质上说,系统会在堆上维护一个动态内存链表,如果被释放,就意味着该块内存可以继续被分配给其他部分,如果内存被释放后再访问,就可能覆盖其他部分的信息,这是一种严重的错误,上述程序第16行中就在释放后仍然写这块内存。

下面的一段程序,就包括了内存动态管理中常见的错误。

#include <stdlib.h>

#include <stdio.h>

int main(int argc,char *argv[])

{ char *p=(char*)malloc(10);

char *pt=p;

int i;

for(i=0;i<10;i++)

{p[i]=’z’;}

delete p;

p[1]=’a’;

free(pt);

return 0;

}

Valgrind提示如下

==25811== Mismatched free() / delete / delete []

==25811== at 0x4A05130: operator delete(void*) (vg_replace_malloc.c:244)

==25811== by 0x400654: main (sample4.c:9)

==25811== Address 0x4C2F030 is 0 bytes inside a block of size 10 alloc'd

==25811== at 0x4A05809: malloc (vg_replace_malloc.c:149)

==25811== by 0x400620: main (sample4.c:4)

==25811==

==25811== Invalid write of size 1

==25811== at 0x40065D: main (sample4.c:10)

==25811== Address 0x4C2F031 is 1 bytes inside a block of size 10 free'd

==25811== at 0x4A05130: operator delete(void*) (vg_replace_malloc.c:244)

==25811== by 0x400654: main (sample4.c:9)

==25811==

==25811== Invalid free() / delete / delete[]

==25811== at 0x4A0541E: free (vg_replace_malloc.c:233)

==25811== by 0x400668: main (sample4.c:11)

==25811== Address 0x4C2F030 is 0 bytes inside a block of size 10 free'd

==25811== at 0x4A05130: operator delete(void*) (vg_replace_malloc.c:244)

==25811== by 0x400654: main (sample4.c:9)

==25811==

==25811== ERROR SUMMARY: 3 errors from 3 contexts (suppressed: 5 from 1)

==25811== malloc/free: in use at exit: 0 bytes in 0 blocks.

==25811== malloc/free: 1 allocs, 2 frees, 10 bytes allocated.

==25811== For counts of detected errors, rerun with: -v

==25811== All heap blocks were freed -- no leaks are possible.

例5.内存泄漏

代码如下

#include <stdlib.h>

int main()

{

char *x = (char*)malloc(20);

char *y = (char*)malloc(20);

x=y;

free(x);

free(y);

return 0;

}

Valgrind提示如下

==19013== Invalid free() / delete / delete[]

==19013== at 0x4A0541E: free (vg_replace_malloc.c:233)

==19013== by 0x4004F5: main (sample5.c:8)

==19013== Address 0x4C2E078 is 0 bytes inside a block of size 20 free'd

==19013== at 0x4A0541E: free (vg_replace_malloc.c:233)

==19013== by 0x4004EC: main (sample5.c:7)

==19013==

==19013== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 5 from 1)

==19013== malloc/free: in use at exit: 20 bytes in 1 blocks.

==19013== malloc/free: 2 allocs, 2 frees, 40 bytes allocated.

==19013== For counts of detected errors, rerun with: -v

==19013== searching for pointers to 1 not-freed blocks.

==19013== checked 66,584 bytes.

==19013==

==19013== LEAK SUMMARY:

==19013== definitely lost: 20 bytes in 1 blocks.

==19013== possibly lost: 0 bytes in 0 blocks.

==19013== still reachable: 0 bytes in 0 blocks.

==19013== suppressed: 0 bytes in 0 blocks.

==19013== Use --leak-check=full to see details of leaked memory.

例6.非法写/读

代码如下

int main()

{

int i, *x;

x = (int *)malloc(10*sizeof(int));

for (i=0; i<11; i++)

x[i] = i;

free(x);

}

Valgrind提示如下

==21483== Invalid write of size 4

==21483== at 0x4004EA: main (sample6.c:6)

==21483== Address 0x4C2E058 is 0 bytes after a block of size 40 alloc'd

==21483== at 0x4A05809: malloc (vg_replace_malloc.c:149)

==21483== by 0x4004C9: main (sample6.c:4)

==21483==

==21483== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 5 from 1)

==21483== malloc/free: in use at exit: 0 bytes in 0 blocks.

==21483== malloc/free: 1 allocs, 1 frees, 40 bytes allocated.

==21483== For counts of detected errors, rerun with: -v

==21483== All heap blocks were freed -- no leaks are possible.

例7.无效指针

代码如下

#include <stdlib.h>

int main()

{

char *x = malloc(10);

x[10] = 'a';

free(x);

return 0;

}

Valgrind提示如下

==15262== Invalid write of size 1

==15262== at 0x4004D6: main (sample7.c:5)

==15262== Address 0x4C2E03A is 0 bytes after a block of size 10 alloc'd

==15262== at 0x4A05809: malloc (vg_replace_malloc.c:149)

==15262== by 0x4004C9: main (sample7.c:4)

==15262==

==15262== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 5 from 1)

==15262== malloc/free: in use at exit: 0 bytes in 0 blocks.

==15262== malloc/free: 1 allocs, 1 frees, 10 bytes allocated.

==15262== For counts of detected errors, rerun with: -v

==15262== All heap blocks were freed -- no leaks are possible.

例8.重复释放

代码如下

#include <stdlib.h>

int main()

{

char *x = malloc(10);

free(x);

free(x);

return 0;

}

Valgrind提示如下

==15005== Invalid free() / delete / delete[]

==15005== at 0x4A0541E: free (vg_replace_malloc.c:233)

==15005== by 0x4004DF: main (sample8.c:6)

==15005== Address 0x4C2E030 is 0 bytes inside a block of size 10 free'd

==15005== at 0x4A0541E: free (vg_replace_malloc.c:233)

==15005== by 0x4004D6: main (sample8.c:5)

==15005==

==15005== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 5 from 1)

==15005== malloc/free: in use at exit: 0 bytes in 0 blocks.

==15005== malloc/free: 1 allocs, 2 frees, 10 bytes allocated.

==15005== For counts of detected errors, rerun with: -v

==15005== All heap blocks were freed -- no leaks are possible.

Valgrind的局限

l Valgrind不对静态数组(分配在栈上)进行边界检查。如果在程序中声明了一个数组:

int main()

{

char x[10];

x[11] = 'a';

}

Valgrind则不会警告你,你可以把数组改为动态在堆上分配的数组,这样就可能进行边界检查了。这个方法好像有点得不偿失的感觉。

l Valgrind占用了更多的内存--可达两倍于你程序的正常使用量。如果你用Valgrind来检测使用大量内存的程序就会遇到问题,它可能会用很长的时间来运行测试。大多数情况下,这都不是问题,即使速度慢也仅是检测时速度慢,如果你用Valgrind来检测一个正常运行时速度就很慢的程序,这下问题就大了。 Valgrind不可能检测出你在程序中犯下的所有错误--如果你不检查缓冲区溢出,Valgrind也不会告诉你代码写了它不应该写的内存。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: