两个程序员遇到的最普遍并且最难处理的问题是覆盖分配内存的尾部以及内存泄露(在他们不需要内存的时候不能释放内存)。
DEBUG
堆提供了强大的工具来解决这类内存分配的问题。
堆函数的调试版本
堆函数的调试版本调用
Release
创建中的标准的或基础版本。当你请求一个内存块的时候,调试堆管理器从基础堆中分配一个稍微比你请求大一点的内存快,并且返回一个指针指向你的块的部分。例如,如果你的程序包含调用:
malloc(10)
,在
Release
创建的时候,
malloc
将调用基础堆分配程序来请求分配
10
个字节的空间;在
Debug
版本中,
malloc
将调用
malloc_dbg
,它将调用基础堆来分配一个你请求的
10
个字节再加
36
个字节的额外内存。所有的在
debug
堆中的内存块用一个单一的链表来连接,顺序是按照分配的顺序。
调试堆程序分配的额外内存用来保存信息,用于将调式内存块连接在一起的指针和在你数据另一边的小缓冲区来捕获分配区域的越界。
当前,块头结构用来存储调试堆的辅助信息定义为下面的形式(
DBGINT.H
):
typedef struct _CrtMemBlockHeader
{
// Pointer to the block allocated just before this one:
struct _CrtMemBlockHeader *pBlockHeaderNext;
// Pointer to the block allocated just after this one:
struct _CrtMemBlockHeader *pBlockHeaderPrev;
char *szFileName; // File name
int nLine; // Line number
size_t nDataSize; // Size of user block
int nBlockUse; // Type of block
long lRequest; // Allocation number
// Buffer just before (lower than) the user's memory:
unsigned char gap[nNoMansLandSize];
} _CrtMemBlockHeader;
/* In an actual memory block in the debug heap,
* this structure is followed by:
* unsigned char data[nDataSize];
* unsigned char anotherGap[nNoMansLandSize];
*/
NoMansLan
缓冲区在用户数据区域的任意一边是
4
个字节的大小,填充一个已知的值,用于调试堆程序来验证用户的内存没有被越界的限制。调试堆也用已知的值来填充新的内存块;如果你选择将
FREED
块保存在堆的连表中(如下面解释),这些块也会被填充已知的值。当前,实际字节值如下:
NoMansLand(0XFD)
这种缓冲区在内存的任意一边,当前填充为
0XFD
,应用程序使用
Freed blocks(0XDD)
该块在
_CRTDBG_DELAY_FREE_MEM_DF
标志被设置的时候始终保持在堆的连接连表中不使用;当前填充
0XDD
。
New object(OXCD)
当他们被分配的时候填充
0XCD