对于程序员来说,最痛苦的就是内存的申请与释放。内存泄露也是程序中经常遇到的问题。为了更好的定位内存泄露问题,我们有必要熟悉一些内存泄露的检测工具。今天主要找到了以下四个内存检测工具,使用起来都比较方便。
安装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)
检测到内存泄露与数组越界的错误
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
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,然后可以执行下列测试程序
#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有垃圾内存回收机制。