1、使用 mtrace
工具
测试代码如下:
#include <stdlib.h>
#include <stdio.h>
#include <mcheck.h>
int main(void)
{
setenv("MALLOC_TRACE", "mtrace.log", 1); // set log filename
mtrace();
char * p1 = malloc(100);
free(p1);
char * p2 = malloc(200);
char * p3 = malloc(300);
char * p4 = malloc(400);
free(p4);
muntrace();
return 0;
}
测试结果如下,打印出了内存泄漏的文件名和行号:
$ gcc -g demo.c
$ ./a.out
$ mtrace a.out mtrace.log
Memory not freed:
-----------------
Address Size Caller
0x000000000256d5f0 0xc8 at /.../demo.c:12
0x000000000256d6c0 0x12c at /.../demo.c:13
2、使用 valgrind
工具
下载:
wget https://sourceware.org/pub/valgrind/valgrind-3.16.1.tar.bz2
安装:
tar jxvf valgrind-3.16.1.tar.bz2
cd valgrind-3.16.1/
./configure
make
sudo make install
查看是否安装成功:
valgrind --version
用 valgrind
测试,有打印出内存泄漏的文件名、函数名、行号 :
$ valgrind --tool=memcheck --leak-check=full ./a.out
==22557== Memcheck, a memory error detector
==22557== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==22557== Using Valgrind-3.16.1 and LibVEX; rerun with -h for copyright info
==22557== Command: ./a.out
==22557==
==22557==
==22557== HEAP SUMMARY:
==22557== in use at exit: 1,012 bytes in 3 blocks
==22557== total heap usage: 9 allocs, 6 frees, 2,344 bytes allocated
==22557==
==22557== 200 bytes in 1 blocks are definitely lost in loss record 1 of 3
==22557== at 0x4C2DF66: malloc (vg_replace_malloc.c:307)
==22557== by 0x40068A: main (demo.c:12)
==22557==
==22557== 300 bytes in 1 blocks are definitely lost in loss record 2 of 3
==22557== at 0x4C2DF66: malloc (vg_replace_malloc.c:307)
==22557== by 0x400698: main (demo.c:13)
==22557==
==22557== 512 bytes in 1 blocks are definitely lost in loss record 3 of 3
==22557== at 0x4C2DF66: malloc (vg_replace_malloc.c:307)
==22557== by 0x4EC3F57: mtrace (mtrace.c:296)
==22557== by 0x400666: main (demo.c:8)
==22557==
==22557== LEAK SUMMARY:
==22557== definitely lost: 1,012 bytes in 3 blocks
==22557== indirectly lost: 0 bytes in 0 blocks
==22557== possibly lost: 0 bytes in 0 blocks
==22557== still reachable: 0 bytes in 0 blocks
==22557== suppressed: 0 bytes in 0 blocks
==22557==
==22557== For lists of detected and suppressed errors, rerun with: -s
==22557== ERROR SUMMARY: 3 errors from 3 contexts (suppressed: 0 from 0)
3、自己实现一个简单的检查内存泄漏的代码
思路是把 malloc
和 free
函数用宏定义
替换成自己的函数,然后保存每次申请和释放的情况,最终输出没有释放的地址,并打印出文件名、行号、函数名。
这里只写了一个简单的 demo,只写了malloc
和free
,还需要再加上 calloc
和 realloc
。
测试结果,可以打印出内存泄漏位置在 debug_demo.c 的第 15 行的 test_malloc_only 函数内:
$ make
rm -f *.out
gcc debug_malloc.c debug_demo.c -g -D MALLOC_DEBUG
./a.out | uniq
$ ./a.out | uniq
addr2line 0x4007ab -e a.out -fsp;
$ addr2line 0x4007ab -e a.out -fsp;
test_malloc_only at debug_demo.c:15
代码如下:
debug_malloc.c:
#include <stdio.h>
#include <stdlib.h>
#include <execinfo.h>
#define N 100
static void * call_p[N];
static void * malloc_p[N];
static int malloc_i = 0;
void* debug_malloc(size_t size)
{
malloc_p[malloc_i] = malloc(size);
if (NULL == malloc_p[malloc_i])
{
exit(-1);
}
call_p[malloc_i] = __builtin_return_address(0);
malloc_i++;
return malloc_p[malloc_i - 1];
}
void debug_free(void *p)
{
size_t size = 0;
int i = 0;
for (i = 0; i < N; ++i)
{
if (malloc_p[i] == p)
{
call_p[i] = NULL;
malloc_p[i] = NULL;
break;
}
}
free(p);
}
void debug_log()
{
int i = 0;
for (i = 0; i < N; ++i)
{
if (call_p[i])
{
printf("addr2line %p -e a.out -fsp; \n", call_p[i]);
}
}
}
debug_demo.c:
#include <stdio.h>
#include <stdlib.h>
#ifdef MALLOC_DEBUG
extern void* debug_malloc(size_t size);
extern void* debug_free(void *p);
extern void debug_log();
#define malloc(size) debug_malloc(size)
#define free(p) debug_free(p)
#endif
#define LEN 32
void test_malloc_only()
{
char *p = (char *)malloc(LEN);
snprintf(p, LEN, "%s %d", "hello", 666 );
}
void test_malloc_free()
{
char *p = (char *)malloc(LEN);
snprintf(p, LEN, "%s %d", "hello", 0 );
free(p);
}
int main(void)
{
int i;
for(i = 0; i < 50; i++)
{
test_malloc_only();
test_malloc_free();
}
#ifdef MALLOC_DEBUG
debug_log();
#endif
return 0;
}
Makefile:
all:
rm -f *.out
gcc debug_malloc.c debug_demo.c -g -D MALLOC_DEBUG
@echo "./a.out | uniq"
也可以考虑把文件名、函数名、行号当做参数传入:
extern void* debug_malloc(size_t size, const char *file, const char *fun, int line);
extern void* debug_free(void *p, const char *file, const char *fun, int line);
#define malloc(size) debug_malloc(size, __FILE__, __FUNCTION__, __LINE__)
#define free(p) debug_free(p, __FILE__, __FUNCTION__, __LINE__)
网友评论