#内存泄露# #dmalloc# dmalloc

dmalloc是一个简单易用的C/C++内存leak检查工具,以一个运行库的方式发布。能够检查出直到程序运行结束还没有释放的内存,并且能够精确指出在哪个源文件的第几行。

dmalloc 主页: http://dmalloc.com

根据官方网址描述支持常见平台:AIX, BSD/OS, DG/UX, Free/Net/OpenBSD, GNU/Hurd, HPUX, Irix, Linux, MS-DOG, NeXT, OSF, SCO, Solaris, SunOS, Ultrix, Unixware, Windoze, and even Unicos on a Cray T3E

目前最新版本: dmalloc-5.5.2.tgz

下载,解压,编译,安装,关于编译安装可参考

#linux# gdb交叉编译arm-linux-gnueabihf-gdb

https://blog.csdn.net/xiaoting451292510/article/details/105166739

编译过程中可能会提示以下错误

dmalloc.h:484:7: error: expected identifier or ‘(’ before ‘__extension__’ char *strndup(const char *string, const DMALLOC_SIZE len);

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
#ifndef DMALLOC_STRDUP_MACRO
/*
 * DMALLOC_PNT strdup
 *
 * DESCRIPTION:
 *
 * Overload of strdup(3).  Allocate and return an allocated block of
 * memory holding a copy of a string.
 *
 * RETURNS:
 *
 * Success - Valid pointer.
 *
 * Failure - 0L
 *
 * ARGUMENTS:
 *
 * string -> String we are duplicating.
 */
extern
char    *strdup(const char *string);

/*
 * DMALLOC_PNT strndup
 *
 * DESCRIPTION:
 *
 * Overload of strndup(3).  Allocate and return an allocated block of
 * memory holding a copy of a string with a maximum length.
 *
 * RETURNS:
 *
 * Success - Valid pointer.
 *
 * Failure - 0L
 *
 * ARGUMENTS:
 *
 * string -> String we are duplicating.
 *
 * len -> Length of the string to duplicate.
 */
extern
char    *strndup(const char *string, const DMALLOC_SIZE len);
#endif /* ifndef DMALLOC_STRDUP_MACRO */

请将源码中的宏DMALLOC_STRDUP_MACRO范围将strndup包裹起来,一般情况下也不建议使用。#linux# #字符串处理# strdup、strndup、strndupa、strdupa

ubuntu16.04-x86-64 安装到默认路径(一般不建议安装到默认路径,请尽量进行指定路径安装)

1
2
3
./configure
make threadscxx
make installthcxx

ubuntu16.04-x86-64安装到当前路径

1
2
3
./configure --prefix=/home/cll/99_temp/memory_leak/dmalloc/dmalloc-5.5.2_ubuntu16.04-x86-64
make threadscxx
make installthcxx

arm-linux-gnueabihf安装到当前路径

1
2
3
./configure --target=arm-linux-gnueabihf --host=arm-linux-gnueabihf --program-prefix=arm-linux-gnueabihf- CC=arm-linux-gnueabihf-gcc --prefix=/home/cll/99_temp/memory_leak/dmalloc/dmalloc-5.5.2_arm-linux-gnueabihf
make threadscxx
make installthcxx

./configure --prefix=/home/cll/99_temp/memory_leak/dmalloc/dmalloc-5.5.2_ubuntu16.04-x86-64

根据相关提示可以编译不同的相应版本

1
2
3
To make the thread version of the library type 'make threads'
To make the C++ version of the library type 'make cxx'
To make the shared version of the library type 'make shlib'

将库xx.a嵌入运行程序,makefile里面增加:-DDMALLOC -DDMALLOC_FUNC_CHECK -ldmallocthcxx。如果是C程序把-ldmallocthcxx修改为-ldmalloc即可,如加入以下红色部分

g++ -Wall -g -DDMALLOC -DDMALLOC_FUNC_CHECK -ldmallocthcxx memleak_test.cpp memleak_test1.cpp memleak_test2.cpp -o memleak_test

执行dmalloc,获取环境变量信息,并把它设置为环境变量。

1
2
3
$ ./dmalloc -b -l logfile -i 100 low
DMALLOC_OPTIONS=debug=0x4e48503,inter=100,log=logfile
export DMALLOC_OPTIONS

执行需要检测的程序,会在同一个目录下生成一个logfile文件,里面就是内存泄漏的信息。

1
./memleak_test

对于任何非malloc/free情況下所发生的内存泄露问题,mtrace并不能找出来。也就是对于new的内存,只能检测出有泄露,但不能定位。

dmalloc支持两种使用方式。

  • 调试程序只进行dmalloc静态库的编译链接(上面介绍的就是这种方式),这种方式的好处是对于代码量比较大的现有程序,无需要关心每个.c文件的编译细节,只需要将dmalloc静态库放在程序依赖的最后面即可。但缺点是针对不同CPU体系需要了解基本的函数返回地址汇编实现,同时即使得到了泄露源的地址变量,但也需要借助gdb、objdump或map文件等手段得到该泄露源的真正文件/行号或函数范围。
  • 使用dmalloc静态库编译链接外,还需要在每个要调试的.c程序文件中加入dmalloc.h文件的引用,这种方式的原理是使用dmalloc.h头文件的宏定义将需要调试的.c程序文件中的malloc替换为dmalloc_malloc,这种方式的好处和上面方式正好相反,不需要了解不同CPU体系的汇编,不需要借助gdb等工具,因为编译宏的替换可以直接使用__FILE__、__LINE__宏,所以得到的调试信息直接是可以看到的文件名/行号。但缺点也很明显,需要保证所有需要调试的.c程序文件,都要引用了dmalloc.h头文件。

只进行dmalloc静态库的编译链接

内存泄露信息如下:

1588152214: 107: Dumping Not-Freed Pointers Changed Since Start:
1588152214: 107: not freed: '0x7fb6d1608f08|s1' (36 bytes) from 'unknown'
1588152214: 107: not freed: '0x7fb6d1608f48|s1' (32 bytes) from 'unknown'
1588152214: 107: not freed: '0x7fb6d1608f88|s1' (28 bytes) from 'unknown'
1588152214: 107: not freed: '0x7fb6d1608fc8|s1' (24 bytes) from 'unknown'
1588152214: 107: not freed: '0x7fb6d160bf48|s1' (20 bytes) from 'unknown'

使用dmalloc静态库编译链接外,还需要在每个要调试的.c程序文件中加入dmalloc.h文件的引用

内存泄露信息如下:

1588151651: 107: 200 1 0 0 memleak_test.cpp:72
1588151651: 107: 100 1 0 0 memleak_test.cpp:71
1588151651: 107: 100 1 0 0 memleak_test.cpp:68
1588151651: 107: 100 1 100 1 memleak_test.cpp:65
1588151651: 107: 100 1 100 1 memleak_test.cpp:67
1588151651: 107: 100 1 0 0 memleak_test.cpp:74
1588151651: 107: 100 1 0 0 memleak_test.cpp:66
1588151651: 107: 100 1 0 0 memleak_test.cpp:64
1588151651: 107: 50 1 0 0 memleak_test.cpp:70
1588151651: 107: 961 11 201 3 Total of 11
1588151651: 107: Dumping Not-Freed Pointers Changed Since Start:
1588151651: 107: not freed: '0x7f1bc74d9f08|s1' (36 bytes) from 'unknown'
1588151651: 107: not freed: '0x7f1bc74d9f48|s1' (32 bytes) from 'unknown'
1588151651: 107: not freed: '0x7f1bc74d9f88|s1' (28 bytes) from 'unknown'