检查内存泄漏

检查程序内存泄漏的办法

一.检查是否有内存泄漏

先看以下一段代码

#include 
#include 
#include 

int main()
{
        char *p = malloc(10);
        char *p1 = malloc(10);
        return 0;
}

很明显我们malloc了一块空间后没有free,存在内存泄漏,那么怎么检测呢。再看下面的代码

#include 
#include 
#include 

int main()
{
        setenv("MALLOC_TRACE", "mymemory.log", 1);
        mtrace();
        char *p = malloc(10);
        char *p1 = malloc(10);
        return 0;
}

这样程序运行后会生成一个mymemory.log的文件,这里保存着我们代码的空间信息。然后再命令行运行

mtrace a.out mymemory.log

(这里的a.out为可执行文件名)
可以看到下面的结果

- 0x000055bfee3f8260 Free 4 was never alloc'd 0x7eff3fb2c50d
- 0x000055bfee3f8470 Free 5 was never alloc'd 0x7eff3faafaae
- 0x000055bfee3f84a0 Free 6 was never alloc'd 0x7eff3fb2c4f8

Memory not freed:
-----------------
           Address     Size     Caller
0x000055bfee3f8900      0xa  at 0x55bfec261709
0x000055bfee3f8920      0xa  at 0x55bfec261717

这说明我们的程序存在内存泄漏
再来看看free后运行的结果

#include 
#include 
#include 

int main()
{
        setenv("MALLOC_TRACE", "mymemory.log", 1);
        mtrace();
        char *p = malloc(10);
        char *p1 = malloc(10);
        free(p);
        free(p1);
        return 0;
}
- 0x000055b6c6eeb260 Free 6 was never alloc'd 0x7f7d2420650d
- 0x000055b6c6eeb470 Free 7 was never alloc'd 0x7f7d24189aae
- 0x000055b6c6eeb4a0 Free 8 was never alloc'd 0x7f7d242064f8
No memory leaks.

这说明程序没有存在内存泄漏

二.分析内存泄漏的位置

先看看程序

  1 #include <mcheck.h>
  2 #include <stdio.h>
  3 #include <stdlib.h>
  4 #include <unistd.h>
  5 void fun()
  6 {
  7         char *p = malloc(10);
  8 }
  9 
 10 
 11 int main()
 12 {
 13 
 14         setenv("MALLOC_TRACE", "mymemory.log", 1);
 15         mtrace();
 16         fun();
 17         int i = 20;
 18 
 19         while(i--)
 20                 sleep(2);
 21         return 0;
 22 }

  1. 首先我们编译的时候一定要加上-g来添加调试信息,否则最后的结果是???。比如

gcc -g demo.c

  1. 命令行运行程序,运行时最好加上&,意思是后台运行,并且他会打印出这个进程的pid

./a.out &

  1. 运行cat /proc/101803/maps,这里的10183为你程序的pid号,注意到这的时候需要保证程序还没有退出,结果如下

cat /proc/101803/maps

wk@ubuntu:~$ cat /proc/101803/maps
56025ad66000-56025ad67000 r-xp 00000000 08:01 2244014                    /home/wk/a.out
56025af66000-56025af67000 r--p 00000000 08:01 2244014                    /home/wk/a.out
56025af67000-56025af68000 rw-p 00001000 08:01 2244014                    /home/wk/a.out
56025c125000-56025c146000 rw-p 00000000 00:00 0                          [heap]
7faeb841a000-7faeb8601000 r-xp 00000000 08:01 262383                     /lib/x86_64-linux-gnu/libc-2.27.so
7faeb8601000-7faeb8801000 ---p 001e7000 08:01 262383                     /lib/x86_64-linux-gnu/libc-2.27.so
7faeb8801000-7faeb8805000 r--p 001e7000 08:01 262383                     /lib/x86_64-linux-gnu/libc-2.27.so
7faeb8805000-7faeb8807000 rw-p 001eb000 08:01 262383                     /lib/x86_64-linux-gnu/libc-2.27.so
7faeb8807000-7faeb880b000 rw-p 00000000 00:00 0 
7faeb880b000-7faeb8834000 r-xp 00000000 08:01 262365                     /lib/x86_64-linux-gnu/ld-2.27.so
7faeb8a1f000-7faeb8a21000 rw-p 00000000 00:00 0 
7faeb8a34000-7faeb8a35000 r--p 00029000 08:01 262365                     /lib/x86_64-linux-gnu/ld-2.27.so
7faeb8a35000-7faeb8a36000 rw-p 0002a000 08:01 262365                     /lib/x86_64-linux-gnu/ld-2.27.so
7faeb8a36000-7faeb8a37000 rw-p 00000000 00:00 0 
7ffc13528000-7ffc13549000 rw-p 00000000 00:00 0                          [stack]
7ffc135fb000-7ffc135fe000 r--p 00000000 00:00 0                          [vvar]
7ffc135fe000-7ffc135ff000 r-xp 00000000 00:00 0                          [vdso]
ffffffffff600000-ffffffffff601000 --xp 00000000 00:00 0                  [vsyscall]

  1. 运行mtrace a.out mymemory.log来获取内存泄漏的代码地址,结果如下
- 0x000056025c125260 Free 3 was never alloc'd 0x7faeb85b450d
- 0x000056025c125470 Free 4 was never alloc'd 0x7faeb8537aae
- 0x000056025c1254a0 Free 5 was never alloc'd 0x7faeb85b44f8

Memory not freed:
-----------------
           Address     Size     Caller
0x000056025c125900      0xa  at 0x56025ad6672c
  1. 从上面两个代码我们可以看到,Caller显示的调用者地址(0x56025ad6672c)在(56025ad66000-56025ad67000)范围中,也就是maps第一行的地方。然后我们把两个地址相减0x56025ad6672c - 56025ad66000 = 0x72c
  2. 然后再通过addr2line命令得到具体代码泄漏的行数,注意-e参数后跟的参数可能是可执行文件名或者库名。具体看maps后面的是什么
wk@ubuntu:~$ addr2line -e a.out 0x72c
/home/wk/demo2.c:7

这样就得出了在demo2.c的第7行出现内存泄漏

你可能感兴趣的:(C语言基础,c语言)