一、基于CRT的内存泄漏检测
windows 下,C运行时库CRT(C Run-time Library),Standard C++ Library包含CRT。CRT将 malloc 和 free 函数映射到它们的调试版本,即 _malloc_dbg 和 _free_dbg,这两个函数将跟踪内存分配和释放。
原理:Debug版本的 CRT定义了一套调试版本的内存分配函数(如_malloc_dbg)。当你包含了CRTDBG.h后,如果当前是Debug工程,且定义了_DEBUG宏,这时,malloc函数会被被映射为_malloc_dbg。调用_malloc_dbg,它将分配一个内存地址,将地址存储到一个列表中,当调用free的时候,肯定还是传入该地址,然后从列表中移除。
#define _CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <crtdbg.h>
void* GetMemory(int num)
{
return (char*)malloc(sizeof(char) * num);
}
int main(int argc, char* argv[])
{
GetMemory(10);
_CrtDumpMemoryLeaks();
system("pause");
return 0;
}
vs 输出窗口:
其中内容具体如下:
唯一的数字标识{63}(在定位泄露很有用)
堆类型:normal block
内存泄露的起始位置:0x003F6FB0
内存泄露的大小:10bytes
内存泄露的前16字节的16进制输出
显示了申请空间的代码行数、未释放的空间大小。
如果把上述代码替换成 new 来执行空间申请,则调试打印:
new最终调用的也是malloc,那new应该也会有效。虽然起作用,但是不现实代码具体位置,原因是new可能经过了几层调用,才调用到了malloc,而且是在CRT库中调用的malloc,打印的地址,也是CRT的地址,显然这是不对的。
operator new 源码:
void *__CRTDECL operator new(size_t) /*_THROW1(std::bad_alloc)*/;
void * operator new[]( size_t cb )
{
void *res = operator new(cb);
RTCCALLBACK(_RTC_Allocate_hook, (res, cb, 0));
return res;
}
void *__CRTDECL operator new(size_t size) _THROW1(_STD bad_alloc)
{
// try to allocate size bytes
void *p;
while ((p = malloc(size)) == 0) //申请空间
if (_callnewh(size) == 0) //若申请失败则调用处理函数
{
// report no memory
static const std::bad_alloc nomem;
_RAISE(nomem); // #define _RAISE(x) ::std:: _Throw(x) 抛出nomem的异常
}
return (p);
}
CRT提供了operator new重载版本
void *__CRTDECL operator new(
size_t cb,
int nBlockUse,
const char * szFileName,
int nLine
)
_THROW1(_STD bad_alloc)
{
/* _nh_malloc_dbg already calls _heap_alloc_dbg in a loop and calls _callnewh
if the allocation fails. If _callnewh returns (very likely because no
new handlers have been installed by the user), _nh_malloc_dbg returns NULL.
*/
void *res = _nh_malloc_dbg( cb, 1, nBlockUse, szFileName, nLine );
RTCCALLBACK(_RTC_Allocate_hook, (res, cb, 0));
/* if the allocation