一个简单的内存泄漏检测C工具

浏览:
字体:
发布时间:2013-12-11 11:03:08
来源:

  这个内存泄漏检测工具很简单,只能检测同一个模块,同一个线程中发送的内存泄漏,对于在编写代码过程中的代码调试有一定的帮助。如果要在集成测试或功能测试中检测内存泄漏,还需借助专门的工具。

1. 先取向malloc,free和calloc这几个标识符的定义:注意这一步非常重要,否则后面的malloc、free和calloc函数会和我们稍后在头文件中定义的宏冲突

// 取消malloc, calloc, free的宏定义#undef malloc#undef calloc#undef free


2. 定义保存内存信息的单向链表

/** * 定义链表节点,表示一个内存泄漏信息 */typedef struct _mem_node{	void *ptr;		// 泄漏内存地址	size_t block;	// 泄漏内存大小	size_t line;	// 泄露发生的代码行	char *filename;	// 泄漏发生的文件名	struct _mem_node *next;	// 下一个节点指针} mem_node;// 定义指向头节点的指针mem_node *head = NULL;


3. 用于将节点加入单项链表的函数

/** * 产生一个节点并加入链表 * @param ptr 分配的内存地址 * @param block 分配的内存单元大小 * @param line 代码行号 * @param filename 文件名称 */static void mem_node_add(void *ptr, size_t block, size_t line, char *filename){	// 产生节点	mem_node *node = malloc(sizeof(mem_node));	node->ptr = ptr;	node->block = block;	node->line = line;	node->filename = filename;	node->next = NULL;	// 加入链表头节点	if (head)	{		node->next = head;		head = node;	}	else		head = node;}

4. 从单项链表中删除节点的函数

/** * 从链表中删除一个节点 * @param ptr 分配的内存地址 */static void mem_node_remove(void *ptr){	// 判断头节点是否存在	if (head)	{		// 处理头节点		if (head->ptr == ptr)		{			// 获取头节点的下一个节点			mem_node *pn = head->next;			// 删除头节点			free(head);			// 令头节点指针指向下一个节点			head = pn;		}		else	// 判断链表是否为空		{			// 指向节点的指针			mem_node *pn = head->next;			// 指向前一个节点的指针			mem_node *pc = head;			// 遍历所有节点			while (pn)			{				// 获取指向下一个节点的指针				mem_node *pnext = pn->next;				if (pn->ptr == ptr)				{					pc->next = pnext;	// 删除当前节点					free(pn);				}				else					pc = pc->next;				pn = pnext;			}		}	}}

5. 显示内存泄露信息报告

/** * 显示内存泄漏信息 */void show_block(){	if (head)	{		// 保存总内存泄漏数量		size_t total = 0;		// 指向头节点的指针		mem_node *pn = head;		// 输出标题		puts("/n/n-------------------------------内存泄漏报告------------------------------------/n");		// 遍历链表		while (pn)		{			mem_node *pnext = pn->next;			// 处理文件名			char *pfile = pn->filename, *plast = pn->filename;			while (*pfile)			{				// 找到/字符				if (*pfile == '//')					plast = pfile + 1;	// 获取/字符的位置				pfile++;			}			// 输出内存泄漏信息			printf("位置:%s(%d), 地址:%p(%dbyte)/n", plast, pn->line, pn->ptr, pn->block);			// 累加内存泄漏总量			total += pn->block;			// 删除链表节点			free(pn);			// 指向下一个节点			pn = pnext;		}		printf("总计内存泄漏:%dbyte/n", total);	}}

6. 定义调试用malloc函数

/** * 用于调试的malloc函数 * @param elem_size 分配内存大小 * @param filename 文件名称 * @param line 代码行号 */void *dbg_malloc(size_t elem_size, char *filename, size_t line){	void *ptr = malloc(elem_size);	// 将分配内存的地址加入链表	mem_node_add(ptr, elem_size, line, filename);	return ptr;}

7. 定义调试用的calloc函数

/** * 用于调试的calloc函数 * @param count 分配内存单元数量 * @param elem_size 每单元内存大小 * @param filename 文件名称 * @param line 代码行号 */void *dbg_calloc(size_t count, size_t elem_size, char *filename, size_t line){	void *ptr = calloc(count, elem_size);	// 将分配内存的地址加入链表	mem_node_add(ptr, elem_size * count, line, filename);	return ptr;}

8. 定义调试用的free函数

/** * 用于调试的free函数 * @param ptr 要释放的内存地址 */void dbg_free(void *ptr){	free(ptr);	// 从链表中删除节点	mem_node_remove(ptr);}

  上述代码应包含在一个C文件中(例如memcheck.c),完成上述步骤,就可以利用这一组函数来检测内存泄露了,需要定义如下头文件,该头文件应该被书写上述函数的C文件include:

#ifndef _MEM_CHECK_H#define _MEM_CHECK_H#include // instead of malloc#define malloc(s) dbg_malloc(s, __FILE__, __LINE__)// instead of calloc#define calloc(c, s) dbg_calloc(c, s, __FILE__, __LINE__)// instead of free#define free(p) dbg_free(p)/** * allocation memory */void *dbg_malloc(size_t elem_size, char *filename, size_t line);/** * allocation and zero memory */void *dbg_calloc(size_t count, size_t elem_size, char *filename, size_t line);/** * deallocate memory */void dbg_free(void *ptr);/** * show memory leake report */void show_block();#endif // _MEM_CHECK_H

  使用的时候只需要包含上述头文件(例如命名为memcheck.h),并将上述C文件引入到项目中即可。测试代码如下:

#ifdef DEBUG#include "memcheck.h"#endifint main(){	int* p;#ifdef DEBUG	atexit(show_block); // 在程序结束后显示内存泄漏报告#endif // DEBUG	// 分配内存并不回收,显示内存泄漏报告	p = (int*)malloc(1000);	return 0;}



>更多相关文章
24小时热门资讯
24小时回复排行
资讯 | QQ | 安全 | 编程 | 数据库 | 系统 | 网络 | 考试 | 站长 | 关于东联 | 安全雇佣 | 搞笑视频大全 | 微信学院 | 视频课程 |
关于我们 | 联系我们 | 广告服务 | 免责申明 | 作品发布 | 网站地图 | 官方微博 | 技术培训
Copyright © 2007 - 2024 Vm888.Com. All Rights Reserved
粤公网安备 44060402001498号 粤ICP备19097316号 请遵循相关法律法规
');})();