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

Linux C程序内存泄露检测

2014-01-15 16:45 369 查看
对于程序员来说,最痛苦的就是内存的申请与释放。内存泄露也是程序中经常遇到的问题。为了更好的定位内存泄露问题,我们有必要熟悉一些内存泄露的检测工具。今天主要找到了以下四个内存检测工具,使用起来都比较方便。

valgrind

 安装valgrind,执行下列程序

#include <stdlib.h>

void func()
{
int *p = malloc(10*sizeof(int));
p[10] = 0;
}

int main()
{
func();
return 0;
}

编译:

 gcc -g -o valgrindtst valgrindtst.c

执行内存检测:

valgrind --tool=memcheck -leak-check=full ./valgrindtst

内存检测结果:

==19896== Memcheck, a memory error detector

==19896== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.

==19896== Using Valgrind-3.9.0 and LibVEX; rerun with -h for copyright info

==19896== Command: ./valgrindtst

==19896==

==19896== Invalid write of size 4

==19896==    at 0x80483DF: func (valgrindtst.c:6)

==19896==    by 0x80483F1: main (valgrindtst.c:11)

==19896==  Address 0x401a050 is 0 bytes after a block of size 40 alloc'd

==19896==    at 0x40072D5: malloc (vg_replace_malloc.c:291)

==19896==    by 0x80483D5: func (valgrindtst.c:5)

==19896==    by 0x80483F1: main (valgrindtst.c:11)

==19896==

==19896==

==19896== HEAP SUMMARY:

==19896==     in use at exit: 40 bytes in 1 blocks

==19896==   total heap usage: 1 allocs, 0 frees, 40 bytes allocated

==19896==

==19896== 40 bytes in 1 blocks are definitely lost in loss record 1 of 1

==19896==    at 0x40072D5: malloc (vg_replace_malloc.c:291)

==19896==    by 0x80483D5: func (valgrindtst.c:5)

==19896==    by 0x80483F1: main (valgrindtst.c:11)

==19896==

==19896== LEAK SUMMARY:

==19896==    definitely lost: 40 bytes in 1 blocks

==19896==    indirectly lost: 0 bytes in 0 blocks

==19896==      possibly lost: 0 bytes in 0 blocks

==19896==    still reachable: 0 bytes in 0 blocks

==19896==         suppressed: 0 bytes in 0 blocks

==19896==

==19896== For counts of detected and suppressed errors, rerun with: -v

==19896== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 12 from 8)

检测到内存泄露与数组越界的错误

mtrace

 libc提供的内存检测工具。一般系统中都自带该工具。

#include <stdlib.h>
#include <mcheck.h>

void func()
{
int *p = (int*)malloc(100*sizeof(int));
}

int main()
{
setenv("MALLOC_TRACE", "logfile",1);
mtrace();
func();
return 0;
}

编译:gcc -g -o mtracetst mtracetst.c

执行程序后,生成logfile文件,内容如下:

= Start

@ ./mtracetst:[0x8048436] + 0x8a35428 0x190

@ /lib/libc.so.6:(clearenv+0x7c)[0x26a87c] - 0x8a35008

@ /lib/libc.so.6:(tdestroy+0x47)[0x318747] - 0x8a35080

@ /lib/libc.so.6:(tdestroy+0x4f)[0x31874f] - 0x8a350a0

内容不太好理解,使用perl语言实现的bin程序mtrace可以将这些内容转换为可读内容,如下:

[root@localhost test]# mtrace logfile

$* is no longer supported at /usr/bin/mtrace line 2.

- 0x0000000008a35008 Free 3 was never alloc'd 0x26a87c

- 0x0000000008a35080 Free 4 was never alloc'd 0x318747

- 0x0000000008a350a0 Free 5 was never alloc'd 0x31874f

Memory not freed:

-----------------

           Address     Size     Caller

0x0000000008a35428    0x190  at 0x8048436

memwatch

 A memory leak detection tool. Basically, you add a header file to your souce code files, and compile with MEMWATCH defined or not. The header file MEMWATCH.H contains detailed instructions. This is a list of some of the features present in version
2.71:
- ANSI C
- Logging to file or user function using TRACE() macro
- Fault tolerant, can repair it’s own data structures
- Detects double-frees and erroneous free’s
- Detects unfreed memory
- Detects overflow and underflow to memory buffers
- Can set maximum allowed memory to allocate, to stress-test app
- ASSERT(expr) and VERIFY(expr) macros
- Can detect wild pointer writes
- Support for OS specific address validation to avoid GP’s (segmentation faults)
- Collects allocation statistics on application, module or line level
- Rudimentary support for threads (see FAQ for details)
- Rudimentary support for C++ (disabled by default, use with care!)

 

下载,解压,在解压目录中,写如下测试程序:

#include <stdlib.h>
#include "memwatch.h"

int main()
{
char *p1 = NULL, *p2 = NULL;
p1 = malloc(100*sizeof(char));
p2 = malloc(1000*sizeof(char));
free(p2);
}


编译: gcc -g -o memwatchtst -DMEMWATCH -DMEMWATCH_STDIO memwatchtst.c memwatch.c执行结果:

[root@localhost memwatch-2.71]# ./memwatchtst

MEMWATCH detected 1 anomalies

在当前目录下生成memwatch.log文件,打开,内容如下:

============= MEMWATCH 2.71 Copyright (C) 1992-1999 Johan Lindh =============

Started at Wed Jan 15 01:30:01 2014

Modes: __STDC__ 64-bit mwDWORD==(unsigned long)

mwROUNDALLOC==8 sizeof(mwData)==32 mwDataSize==32

Stopped at Wed Jan 15 01:30:01 2014

unfreed: <1> memwatchtst.c(7), 100 bytes at 0x9ea11f0   {FE FE FE FE FE FE FE FE FE FE FE FE FE FE FE FE ................}

Memory usage statistics (global):

 N)umber of allocations made: 2

 L)argest memory usage      : 1100

 T)otal of all alloc() calls: 1100

 U)nfreed bytes totals      : 100

gc

垃圾回收器、内存泄露检测

安装gc,然后可以执行下列测试程序

#include <gc.h>
#include <stdio.h>
#include <stdlib.h>
#include <gc/leak_detector.h>
void test()
{
int i;
char *p;
for(i=0; i < 10000; i++)
{
p = GC_malloc(100000*sizeof(int));
if(NULL == p)
{
printf("NO memory\n");
break;
}
}

}

void chkmem()
{
int *p[10];
int i;
GC_find_leak = 1;
for(i=0; i < 10; i++)
{
p[i] = (int *)malloc(sizeof(int)+i);
}
for(i=0; i<7;i++)
{
free(p[i]);
}
for(i=3; i < 10; i++)
{
p[i] = (int *)malloc(sizeof(int)+i);
}
CHECK_LEAKS();
}
int main()
{
test();
chkmem();
}

编译:

 export export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/lib

 gcc -g -o gctst gctst.c -lgc

执行结果:

[root@localhost test]# ./gctst

Leaked composite object at start: 0x93d2000, appr. length: 400008

Leaked composite object at start: 0x93b2fa0, appr. length: 16

Leaked composite object at start: 0x93b2fb0, appr. length: 16

Leaked composite object at start: 0x93b2fc0, appr. length: 16

Leaked composite object at start: 0x94f8000, appr. length: 400008

Leaked composite object at start: 0x9496000, appr. length: 400008

Leaked composite object at start: 0x9434000, appr. length: 400008

[root@localhost test]#

注:test函数说明gc有自动回收内存的机制;chkmem函数说明,gc可以检测内存泄露

 

valgrind和memwatch的输出信息比较适合我们的阅读习惯,可以很容易定位内存泄露的位置。

gc有垃圾内存回收机制。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息