小型的嵌入式应用中常常会出现许多内存问题,不少状况下难以定位问题出如今哪里。linux
我在 sourceforge 上找了些检测 C 内存泄漏的工具,感受比较易用的是 memleak,下面就来简要介绍一下它的使用。函数
下载获得的 memleak 压缩包大小不到 15 kB,解压后只有两个文件:memleak.c 和 memleak.h。在使用过程当中只须要包含头文件 memleak.h 就可使用 memleak 提供的几个易用而有效的内存检测函数了。工具
memleak的原理是利用C语言的宏调用来替代原有的函数调用,好比咱们在代码中调用malloc(s),实际是调用了:dbg_malloc(s),这个宏定义在 memleak.h 中给出:
#define malloc(s) (FILE_LINE, dbg_malloc(s))this
memleak 维护了一个链表,在这个链表中保存着程序中对内存函数调用的记录,这些函数包括:malloc、calloc、realloc、free。每次调用这些函数时,就会更新这个链表。
有了这个表,咱们就能够在适当的位置调用 memleak 提供的函数,显示一些重要的信息,包括 malloc、calloc、realloc、free调用的次数,申请及分配的内存数,调用的文件和位置等等,信息很是详细。有了这些功能,咱们就很容易定位内存使用的错误源。spa
因为 memleak 在某些交叉编译器下不能正常编译经过,这里我将 memleak.c 中的结构体 struct head 修改以下:.net
struct head { struct head *addr; size_t size; char *file; unsigned line; /* two addresses took the same space as an address and an integer on many archs => usable */ union lf { struct { struct head*prev, *next; } list; struct { char *file; unsigned line; } free; } u; };memleak.c 文件中其它调用到 head 中共用体 u 的地方也要作相应的修改。
memleak 提供了如下几个函数接口:调试
extern void dbg_init(int history_length); extern int dbg_check_addr(char *msg, void *ptr, int opt); extern void dbg_mem_stat(void); extern void dbg_zero_stat(void); extern void dbg_abort(char *msg); extern void dbg_heap_dump(char *keyword); extern void dbg_history_dump(char *keyword); extern void dbg_catch_sigsegv(void);详细的介绍请查看 memleak.c 头部的注释或查看源代码理解。
下面举个简单的例子:code
#include #include #include "memleak.h" int main(void) { char * s, * t; dbg_init(10); s = (char *)malloc(100); // 申请 100 bytes t = (char *)malloc(11); // 再申请 11 bytes free(s); // 释放 100 bytes s = (char *)malloc(80); // 从新申请 80 bytes dbg_heap_dump(""); // 显示调用栈 dbg_mem_stat(); // 显示调用统计 free(t); // 释放 11 bytes free(s); // 释放 80 bytes dbg_mem_stat(); // 再次显示调用统计 return 0; }编辑后保存为 test.c,与 memleak.c 和 memleak.h 放于同一目录下。
CC = gcc EXEC = test CSRC = test.c memleak.c OBJS = $(patsubst %.c,%.o, $(CSRC)) all: $(EXEC) $(EXEC): $(OBJS) $(CC) $(OBJS) $(LDFLAGS) $(LDLIBS) -o $@ $(OBJS): %.o : %.c $(CC) $(CFLAGS) -c $< -o $@ clean: -rm -f $(EXEC) *.elf *.gdb *.o也保存于同一目录,在该目录下 make 编译,执行 ./test 后输出以下:
***** test.c:14: heap dump start (alloc: test.c:11 size: 11) (alloc: test.c:13 size: 80) ***** test.c:14: heap dump end test.c:15: m: 3, c: 0, r: 0, f: 1, mem: 91 test.c:18: m: 3, c: 0, r: 0, f: 3, mem: 0怎么样,很简单吧?
memleak 中还有一个函数 dbg_catch_sigsegv(void),能够绑定系统出现 SIGSEGV 信号时的处理函数,咱们能够经过修改 memleak.c 中的 sigsegv_handler,自定义这个 SIGSEGV 信号处理函数。不知道 uClinux 下的 SIGSEGV 信号是否也存在,有的话调试一些内存问题就更容易了。blog
最后从网上摘来一段 SIGSEGV 的介绍:接口
SIGSEGV --- Segment Fault. The possible cases of your encountering this error are: 1.buffer overflow --- usually caused by a pointer reference out of range. 2.stack overflow --- please keep in mind that the default stack size is 8192K. 3.illegal file access --- file operations are forbidden on our judge system.