Chinaunix首页 | 论坛 | 博客
  • 博客访问: 602853
  • 博文数量: 149
  • 博客积分: 7191
  • 博客等级: 少将
  • 技术积分: 1561
  • 用 户 组: 普通用户
  • 注册时间: 2005-12-19 14:15
文章分类

全部博文(149)

文章存档

2013年(1)

2011年(2)

2010年(14)

2009年(29)

2008年(26)

2007年(31)

2006年(32)

2005年(14)

分类: C/C++

2011-03-11 09:29:11

    这是以前写的一篇案例,供大家参考。

内存泄露的主要原因在于随着代码量的增大,编码者不能完全跟踪内存分配的状况,当前的编译器对此又没有很好的解决办法,况且动态内存分配是在程序运行中根据具体情况生成的,具有不确定性。

本案例将在程序的调试阶段,通过链表的方式对内存的分配和释放进行实时记录和跟踪,达到检测和避免内存泄露的目的。

欲达到这个目的,需要解决三个问题:链表的实现,malloc的封装,free的封装。

链表,要构造一个适合CC++使用的链表,可以方便的插入,检索和移除链表节点。本案例将采用contiki操作系统中的单向链表结构。

Malloc通过宏的方式进行封装,实现分配指针的检测,和分配信息录入链表的工作。

Free通过宏的方式进行封装,实现分配空间的释放,和分配信息的移除工作。

程序的最后,要提供信息打印,将泄露内存打印出来。

Contiki是一款非常优秀的嵌入式操作系统,其优势之一就是程序的模块化很强,可以根据个人需求,从中拾取相应的模块使用,而代码几乎不需要修改。本案例中用到的单向链表便是一个例子。需要使用contiki的链表实现,只要从其内核中拿出list.clist.h两个文件,只需要进行必要的路径修改。其他的不需要修改。

其使用方法非常简单,在使用时,通过LIST宏的方式,生成自己需要使用的链表。定义自己的链表节点结构体。定义节点结构体需要注意的是,结构体的第一个元素必须是指向该结构体实例下一个实例的指针,命名为next。该处巧妙的利用了内存重合的优点,也是contiki设计比较经典的地方之一。

该案例中定义的结构体如下:

struct Tmemleak{

       struct Tmemleak *next; // list 定义保持一致

       void        *pMalloc;

       char       achFilename[64];

       int           nLine;

       int           nSize;

};

分别记录了分配内存的地址,内存分配的文件名,行号和分配内存的大小。程序启动后,需要对链表进行简单的初始化即可。以后便可以容易的进行链表操作。

Malloc通过宏的方式进行重构,使其具有内存指针检测和分配信息录入的功能。首先进行欲存储分配空间指针的检测,如果其值不为NULL,严谨的讲,其指向一有效内存空间,还未释放,不能对其委以重任。

检测通过后,向其分配有效空间。并生成链表元素,记录该分配动作,将其加入链表。

Free通过宏的方式进行重构,首先检测其是否有效,有效则释放。释放后从链表中移除相应的记录信息,并将记录信息所用内存空间收回。最后,要将指针指向NULL,避免不必要的错误。

在程序的最后,对链表进行遍历,将内存泄露信息打印出来。并将分配内存进行释放。

分配数组为释放的程序打印示例如下:

该结果表示main.c文件中的第9行,分配了50个字节的空间,没有释放。

现有程序想使用该模块进行测试的方法如下:

Makefile中进行MEM_DEBUG的宏定义,以开启内存调试模式。并将list.cmemleak.c加入编译范围中。

在需要该调试的源文件中,引用头文件memleak.h。在主函数main()的开始处,调用memleak_init()函数进行初始化。

main()函数的结尾调用memleak_end()输出结果。

通过全文替换的功能,将free替换成FREE

查找malloc关键词,将语句x = malloc(y),修改成MALLOC(x, y)

如果要进行版本发布,关闭内存调试功能,只要将Makefile中的-DMEM_DEBUG注释掉即可。


阅读(1235) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~