闲着没事的时候分析了一下,才发现问题其实很简单。msvcrtd.dll对每次内存申请都进行计数,当计数值达到设定的某个值时,就会调用_CrtDbgBreak()。MSDN对_CrtDbgBreak的说明是:Sets a break point on a particular line of code,其实_CrtDbgBreak在X86下只有一条指令就是int 3(0xCC)。 在dbgheap.c中定义了下面两个变量: static long _lRequestCurr = 1; /* Current request number */ extern "C" _CRTIMP long _crtBreakAlloc = -1L; /* Break on allocation by request number */ _lRequestCurr表示当前的申请次数,_crtBreakAlloc表示当内存申请次数达到某个值时break,即调用_CrtDbgBreak。详情可参考debugheap.c中的_heap_alloc_dbg_impl函数: lRequest = _lRequestCurr; /* break into debugger at specific memory allocation */ if (_crtBreakAlloc != -1L && lRequest == _crtBreakAlloc) _CrtDbgBreak(); VC6附带的dbgheap.c中没有添加_crtBreakAlloc != -1L的判断,而是: if (lRequest == _crtBreakAlloc) _CrtDbgBreak(); _lRequestCurr初始化为1,每次申请内存都加1,当_lRequestCurr为-1时在VC6的dbgheap.c中就会触发int 3导致程序退出,而在新的版本中添加了_crtBreakAlloc != -1L的判断,所以默认的情况下是不会触发int 3 退出的。 可以通过调用_CrtSetBreakAlloc设置_crtBreakAlloc的值,当我们设置了新的_crtBreakAlloc,而且_crtBreakAlloc等于_lRequestCurr时就会触发int 3。
C:PROGRAM FILESVISUAL STUDIOMyProjectsleaktestleaktest.cpp(20) : {18} normal block at 0x00780E80, 64 bytes long.
Data: < > CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD Object dump complete. 如果不使用 #define _CRTDBG_MAP_ALLOC 语句,内存泄漏转储如下所示: Detected memory leaks! Dumping objects -> {18} normal block at 0x00780E80, 64 bytes long. Data: < > CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD Object dump complete.
第一种比较简单,就是已经把内存泄露映射到源文件的,可以直接在"输出"窗口中双击包含文件名和行号的行。例如 Detected memory leaks! Dumping objects -> C:PROGRAM FILESVISUAL STUDIOMyProjectsleaktestleaktest.cpp(20) : {18} normal block at 0x00780E80, 64 bytes long. Data: < > CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD Object dump complete. C:PROGRAM FILESVISUAL STUDIOMyProjectsleaktestleaktest.cpp(20)
就是源文件名称和行号。
第二种比较麻烦,就是不能映射到源文件的,只有内存分配块号。 Detected memory leaks! Dumping objects -> {18} normal block at 0x00780E80, 64 bytes long. Data: < > CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD Object dump complete.