Linux C内存泄露检测工具

内存泄漏检查方法(for Linux)
如果你更想读原始文档, 请参考glibc info的”Allocation Debugging”一章 (执行info libc);
glibc提供了一个检查内存泄漏的方法, 前提是你的程序使用glibc的标准函数分配内存(如malloc, alloc…):
1. 在需要内存泄漏检查的代码的开始调用void mtrace(void) (在mcheck.h中有声明). mtrace为malloc等函数安装hook, 用于记录内存分配信息.在需要内存泄漏检查的代码的结束调用void muntrace(void).
注意: 一般情况下不要调用muntrace, 而让程序自然结束. 因为可能有些释放内存的的代码要到muntrace之后才运行.
2. 用debug模式编译被检查代码(-g或-ggdb)
3. 设置环境变量MALLOC_TRACE为一文件名, 这一文件将存有内存分配信息.
4. 运行被检查程序, 直至结束或muntrace被调用.
5. 用mtrace命令解析内存分配Log文件($MALLOC_TRACE)
(mtrace foo $MALLOC_TRACE, where foo is the executible name)
如果有内存泄漏, mtrace会输出分配泄漏内存的代码位置,以及分配数量.

其他东西
1. 可以将mtrace, muntrace放入信号处理函数(USR1, USR2), 以动态地进行内存泄漏检查控制.
2. mtrace是个perl代码, 如果你对符号地址与代码文本的转换感兴趣, 可以读一下.
3. again, 尽量不要用muntrace()

For C++ Leak:
检查内存泄漏的方法除glibc提供外;
还可以试试一些专用的程序;如:
ccmalloc

http://www.inf.ethz.ch/personal/biere/projects/ccmalloc/ccmalloc-english.html

mpatrol

http://www.cbmamiga.demon.co.uk/mpatrol/

这俩个工具的功能相当不错,能对程序进行相当全面的检查

01 #include <stdlib.h>

02 #include <mcheck.h>
03 
04 void func(void)
05 {
06     int* ptr = malloc(10 * sizeof(int));
07     //free(ptr);          
08 }
09 
10 int main(void)
11 {
12     setenv(“MALLOC_TRACE”, ”output_file_name”, 1);
13     mtrace();
14     func();
15     return 0;
16 }

# gcc test.c -o test -g
# ./test
# more  output_file_name 
= Start
@ ./test:[0x80483e6] + 0x804a470 0×28
@ /lib/tls/i686/cmov/libc.so.6:(clearenv+0x7c)[0xb7e449ac] - 0x804a008
@ /lib/tls/i686/cmov/libc.so.6:(tdestroy+0×47)[0xb7eec6d7] - 0x804a0c0
@ /lib/tls/i686/cmov/libc.so.6:(tdestroy+0x4f)[0xb7eec6df] - 0x804a0e8

# mtrace output_file_name
- 0x0804a008 Free 3 was never alloc’d 0xb7e449ac
- 0x0804a0c0 Free 4 was never alloc’d 0xb7eec6d7
- 0x0804a0e8 Free 5 was never alloc’d 0xb7eec6df

Memory not freed:
—————–
0  Address     Size     Caller
0x0804a470     0×28  at 0x80483e6

01 #include <stdlib.h>
02 #include <mcheck.h>
03 
04 void func(void)
05 {
06     int* ptr = malloc(10 * sizeof(int));
07     free(ptr);          
08 }
09 
10 int main(void)
11 {
12     setenv(“MALLOC_TRACE”, ”output_file_name”, 1);
13     mtrace();
14     func();
15     return 0;
16 }

# more  output_file_name 
= Start
@ ./test:[0x8048426] + 0x804a470 0×28
@ ./test:[0x8048434] - 0x804a470
@ /lib/tls/i686/cmov/libc.so.6:(clearenv+0x7c)[0xb7e149ac] - 0x804a008
@ /lib/tls/i686/cmov/libc.so.6:(tdestroy+0×47)[0xb7ebc6d7] - 0x804a0c0
@ /lib/tls/i686/cmov/libc.so.6:(tdestroy+0x4f)[0xb7ebc6df] - 0x804a0e8 

0×8048426 分配内存空间的指令地址
0x804a470 malloc分配的内存空间己地址
+         表示分配内存
-         表示释放内存

# mtrace output_file_name 
- 0x0804a008 Free 4 was never alloc’d 0xb7e149ac
- 0x0804a0c0 Free 5 was never alloc’d 0xb7ebc6d7
- 0x0804a0e8 Free 6 was never alloc’d 0xb7ebc6df
No memory leaks.

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

void func(void)
{
    int* ptr = malloc(10 * sizeof(int));
    //free(ptr);         
}

int main(void)
{
    setenv(“MALLOC_TRACE”, ”output_file_name”, 1);
    mtrace();
    func();
    while (1)
    {
        muntrace();
    }
    return 0;
}

$ ./a.out &
$ more output_file_name 
= Start
@ ./a.out:[0x8048426] + 0x804a468 0×28

= End

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

void func(void)
{
int* ptr = malloc(10 * sizeof(int));
//free(ptr);
}

int main(void)
{
setenv(“MALLOC_TRACE”, ”output_file_name”, 1);
mtrace();
func();
while (1)
{
sleep (1);
func ();
muntrace();
}
return 0;
}

= Start
@ ./a.out:[0x8048456] + 0x804a468 0×28
@ ./a.out:[0x8048456] + 0x804a498 0×28
= End
虽然while中反复调用func()但是此处只检测到两次(while外一次,while内一次)

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

void func(void)
{
int* ptr = malloc(10 * sizeof(int));
//free(ptr);
}

int main(void)
{
setenv(“MALLOC_TRACE”, ”output_file_name”, 1);
mtrace();
func();
while (1)
{
sleep (1);
func ();
//muntrace();
}
return 0;
}

这种使用方式,进程中守护任务,所以output_file_name不会马上有内存,需要等一会儿

函数各自生成自己的内存泄露检测报告,这样比较麻烦
———————————————
#include <stdlib.h>
#include <mcheck.h>
#include <stdio.h>

void func(void)
{
char buff[128];
snprintf (buff, sizeof (buff), ”%s”, __FUNCTION__);
setenv(“MALLOC_TRACE”, buff, 1);
mtrace();
int* ptr = malloc(10 * sizeof(int));
//free(ptr);
muntrace();
}

void test()
{
char buff[128];
snprintf (buff, sizeof (buff), ”%s”, __FUNCTION__);
setenv(“MALLOC_TRACE”, buff, 1);
mtrace();
int* ptr = malloc(10 * sizeof(int));
//free(ptr);
muntrace();
}

void task()
{
char buff[128];
snprintf (buff, sizeof (buff), ”%s”, __FUNCTION__);
setenv(“MALLOC_TRACE”, buff, 1);
mtrace();
int* ptr = malloc(10 * sizeof(int));
//free(ptr);
while (1)
{
usleep (10);
/* 如果不在这里调用muntrace,将不能生成检测报告 */
muntrace();
}
}

int main(void)
{

//mtrace();
func();
test();
task();

return 0;
}

普通函数统一报告,有无限循环的函数单独生成报告
———————————————
#include <stdlib.h>
#include <mcheck.h>
#include <stdio.h>

void func(void)
{
int* ptr = malloc(10 * sizeof(int));

}

void test()
{
int* ptr = malloc(10 * sizeof(int));
}

void task()
{
char buff[128];
snprintf (buff, sizeof (buff), ”%s”, __FUNCTION__);
setenv(“MALLOC_TRACE”, buff, 1);
mtrace();
int* ptr = malloc(10 * sizeof(int));
while (1)
{
usleep (10);
/* 如果不在这里调用muntrace,将不能生成检测报告 */
muntrace();
}
}

int main(void)
{
char buff[128];
snprintf (buff, sizeof (buff), ”%s”, __FUNCTION__);
setenv(“MALLOC_TRACE”, buff, 1);
mtrace();
func();
test();
task();

return 0;
}

创建线程前检测一次,并结束检测;线程自行检测;线程创建后不能再进行检测,
如果需要检测,则不能调用muntrace(),但是检测还是会失效
———————————————
#include <stdlib.h>
#include <mcheck.h>
#include <stdio.h>
#include <pthread.h>

void func(void)
{
int* ptr = malloc(10 * sizeof(int));

}

void test()
{
int* ptr = malloc(100 * sizeof(int));
}

void task()
{
char buff[128];
snprintf (buff, sizeof (buff), ”%s”, __FUNCTION__);
setenv(“MALLOC_TRACE”, buff, 1);
mtrace();
int* ptr = malloc(1000 * sizeof(int));
while (1)
{
usleep (10);
/* 如果不在这里调用muntrace,将不能生成检测报告 */
muntrace();
}
}

int main(void)
{
pthread_t id;
int i, ret;

char buff[128];
snprintf (buff, sizeof (buff), ”%s%d”, __FUNCTION__, __LINE__);
setenv(“MALLOC_TRACE”, buff, 1);
mtrace();
func();
test();
muntrace();

ret = pthread_create(&id, NULL, (void *)task, NULL);
if (ret != 0)
{
printf(“Create pthread error!
“);
exit(1);
}

#if 0 /* 创建线程(线程自行负责检测)后,就不能再检测了,否则会有段错误 */
snprintf (buff, sizeof (buff), ”%s%d”, __FUNCTION__, __LINE__);
setenv(“MALLOC_TRACE”, buff, 1);
mtrace();
test();
//muntrace();
#endif

sleep(1);
//while (1) {}
return 0;
}

发表评论

电子邮件地址不会被公开。 必填项已用 * 标注

您可以使用这些 HTML 标签和属性: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>