FENSE_LOCK 获取对链表st_Head的操作权
FENSE_UNLOCK 释放对链表st_Head的操作权
考虑到的在多线程环境中,可能有多个线程同时用Fense进行内存管理,而Fense使用的链表st_Head是全局变量,因此提供了以上2个宏来实现对 st_Head的互斥访问。宏的具体定义依赖于用户所在的软件环境,用户可自行实现。对于单线程系统,仅需将这2个宏定义为空即可。
为便于使用,Fense的头文件中还包括了以下定义,使得用户基本不用改动现有的源代码就可引入Fense。
#define malloc(size) Fense_Malloc(size,_FILE_,_LINE_)
#define free(ptr) Fense_Free(ptr,_FILE_,_LINE_)
#define realloc(ptr,new_size) Fense_Realloc(ptr,new_size,_FILE_,_LINE_)
#define colloc(num,size) Fense_Calloc(num,size,_FILE_,_LINE_)
3 运行时控制
Fense 监测内存的功能可以在运行动态地开关。此功能通过将全局变量st_Disbaled赋值为零或非零来实现。在调试过程中,可以在调试器中即时修改 st_Disabled的值来控制Fense的行为,省去了重编译源代码的需要。对于那些需要大量编译时间的大型工程或交叉平台开发的软件项目来说,这是非常有利的。
4 Fense的具体实现
Fense 提供Fense_Malloc、Fense_Free、Fense_Realloc及Fense_Calloc等内存管理函数,功能和调用形式与C语言中的malloc、free、realloc和calloc保持一致。限于篇幅,这里仅对Fense_Malloc和Fense_Free的实现过程做一个简单描述,具体实现请见本刊网络补充版。
void *Fense_Malloc(size_t size,char *file,unsigned long line)
{
//检查Fense的运行时开关,如果Fense被关闭,则调用malloc;
//分配并返回;
//检查是否零分配,如有则提示警告信息后返回0(用户定制选项);
//分配内存,包括链表节点区域和前/后监测区域;
//初始化链表节点,保存分配内存的信息,包括分配的大小、所在文件名和行号;
//将此节点插入链表st_Head;
//为本节点区域计算校验和;
//用预设值初始化前/后监测区域;
//用预设值填充用户内存区域(用户定制选项);
//返回用户内存区域的起始位置
}
void Fense_Free(void *uptr,char *file,unsigned long line)
{
//检查Fense的运行时开关,如果Fense初关闭,则调用free释译并返回;
//检查所有Fense管理下的动态内存(用户定制选项);
//判断当前内存块是否在链表st_Head中,如果不在则提示;
//警靠信息,退出(用户定制选项);
//检查当前内存块是否存在越界操作;
//将当前内存块的相应的链表节点从st_Head中删除;
//重新计算当前节点的前后相邻节点的校验和;
//用预设值填充被释放的内存区(用户定制选项);
//调用free释放当前的内存块
}
(文中代码在Visual C++6.0、Borland C++ 3.1及CrossCode C 7.4环境中编译通过)
结束语
作为对C程序运行时的内存错误进行监测的代码模块,Fense能发现几乎所有的内存泄漏和绝大多数的越界操作,并尽可能地记录了改正程序错误所需要的信息;有效地减少了程序设计人员的调试时间,在实际嵌入式产品开发中取得了很好的效果。