尽管这个概念已经让人说滥了 ,还是想简单记录一下, 以备以后查询。
运行一下代码
#ifdef _DEBUG
#define DEBUG_CLIENTBLOCK new( _CLIENT_BLOCK, __FILE__, __LINE__)
#else
#define DEBUG_CLIENTBLOCK
#endif
#define _CRTDBG_MAP_ALLOC
#include
#ifdef _DEBUG
#define new DEBUG_CLIENTBLOCK
#endif
int main(int argc, char* argv[])
{
char* p = new char();
char* pp = new char[10];
char* ppp = (char*)malloc(10);
_CrtDumpMemoryLeaks();
return 0;
}
运行以后控制台会显示一下信息,会检测出内存泄漏
Detected memory leaks!
Dumping objects ->
c:\users\leonjo\documents\visual studio 2015\projects\consoleapplication1\
consoleapplication1\consoleapplication1.cpp(20) : {67} normal block at 0x00590C88, 10 bytes long.
Data: < > CD CD CD CD CD CD CD CD CD CD
c:\users\leonjo\documents\visual studio 2015\projects\consoleapplication1\
consoleapplication1\consoleapplication1.cpp(19) : {66} client block at 0x00590C50, subtype 0, 10 bytes long.
Data: < > CD CD CD CD CD CD CD CD CD CD
c:\users\leonjo\documents\visual studio 2015\projects\consoleapplication1\
consoleapplication1\consoleapplication1.cpp(18) : {65} client block at 0x0058E8A0, subtype 0, 1 bytes long.
Data: < > 00
Object dump complete.
The program '[3068] ConsoleApplication1.exe' has exited with code 0 (0x0).
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 fails, we throw std::bad_alloc */
if (res == 0)
{
static const std::bad_alloc nomem;
_RAISE(nomem);
}
return res;
}
这样Crt会把此次分配内存的文件名和行号以及大小等记录下来,最后当调用用_CrtDumpMemoryLeaks(); 时如果还没释放就会打印出来。
int main(int argc, char* argv[])
{
_CrtSetBreakAlloc(67);
char* p = new char();
char* pp = new char[10];
char* ppp = (char*)malloc(10);
_CrtDumpMemoryLeaks();
return 0;
}
代码运行过程会自动切到断点
(3)如果程序有多个出口或是有涉及到全局变量, 可以通过_CrtSetDbgFlag 设置标志让程序退出时自动打印泄露 , 比如
int main(int argc, char* argv[])
{
_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
char* p = new char();
char* pp = new char[10];
char* ppp = (char*)malloc(10);
return 0;
}
Detected memory leaks!
Dumping objects ->
c:\users\leonjo\documents\visual studio 2015\projects\consoleapplication1\
consoleapplication1\consoleapplication1.cpp(21) : {67} normal block at 0x00680C88, 10 bytes long.
Data: < > CD CD CD CD CD CD CD CD CD CD
c:\users\leonjo\documents\visual studio 2015\projects\consoleapplication1\
consoleapplication1\consoleapplication1.cpp(20) : {66} client block at 0x00680C50, subtype 0, 10 bytes long.
Data: < > CD CD CD CD CD CD CD CD CD CD
c:\users\leonjo\documents\visual studio 2015\projects\consoleapplication1\
consoleapplication1\consoleapplication1.cpp(19) : {65} client block at 0x0067E8A0, subtype 0, 1 bytes long.
Data: < > 00
Object dump complete.
The program '[6024] ConsoleApplication1.exe' has exited with code 0 (0x0).
#include
#ifdef _DEBUG
#define DEBUG_CLIENTBLOCK new( _CLIENT_BLOCK, __FILE__, __LINE__)
#else
#define DEBUG_CLIENTBLOCK
#endif
#define _CRTDBG_MAP_ALLOC
#include
#ifdef _DEBUG
#define new DEBUG_CLIENTBLOCK
#endif
int main(int argc, char* argv[])
{
_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
char* p = new char();
char* pp = new char[10];
char* ppp = (char*)malloc(10);
char d;
char* p1 = new(&d) char('a');
return 0;
}
1>------ Build started: Project: ConsoleApplication1, Configuration: Debug Win32 ------
1> ConsoleApplication1.cpp
1>c:\program files (x86)\windows kits\10\include\10.0.10240.0\ucrt\crtdbg.h(302): warning C4005: '_malloca': macro redefinition
1> c:\program files (x86)\windows kits\10\include\10.0.10240.0\ucrt\malloc.h(120): note: see previous definition of '_malloca'
1>c:\users\leonjo\documents\visual studio 2015\projects\consoleapplication1\consoleapplication1\consoleapplication1.cpp(26): error C2059: syntax error: '&'
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
#ifdef _DEBUG
#define DEBUG_CLIENTBLOCK new( _CLIENT_BLOCK, __FILE__, __LINE__)
#else
#define DEBUG_CLIENTBLOCK
#endif
#define _CRTDBG_MAP_ALLOC
#include
#ifdef _DEBUG
#define new DEBUG_CLIENTBLOCK
#endif
#include
你应该把 #include
//MyClass.cpp
#include "myclass.h"
#include
//MemLeakChecker.h
#include
并且确保使用该方法的CPP文件中不能使用operator new 的placement 的方法。否则会报错
如果使用了公共头文件,有各别cpp中使用了new placement导致无法编译,可以使用#undef new 宏
例如一下例子使用了new的placement方法,使用#undef new解除重载new 可以正常编译,并且输出内存泄漏的行号。只是会无法定位到文件和行号。
但是有的时候知道了泄漏的号,可以使用 _CrtSetBreakAlloc(67); 这样可以解决许多内存泄漏的难题。
(9)简单判断某个独立函数有没有内存泄露可以用下面的方法:
class DbgMemLeak
{
_CrtMemState m_checkpoint;
public:
explicit DbgMemLeak()
{
_CrtMemCheckpoint(&m_checkpoint);
};
~DbgMemLeak()
{
_CrtMemState checkpoint;
_CrtMemCheckpoint(&checkpoint);
_CrtMemState diff;
_CrtMemDifference(&diff, &m_checkpoint, &checkpoint);
_CrtMemDumpStatistics(&diff);
_CrtMemDumpAllObjectsSince(&diff);
};
};
int _tmain(int argc, _TCHAR* argv[])
{
DbgMemLeak check;
{www.2cto.com
char* p = new char();
char* pp = new char[10];
char* ppp = (char*)malloc(10);
}
return 0;
}
最后贴一个在项目中可以使用的头文件,
UT_DetectMemLeak.h
#pragma once
#ifndef _UT_DETECT_MEMLEAK_H
#define _UT_DETECT_MEMLEAK_H
#if defined(_NEW_) //Checked that whether the ::operator new placement has been used.
#define DebugCodeCRT(m)
#else
#ifdef _DEBUG
#define new DEBUG_CLIENTBLOCK
#define DebugCodeCRT(m) {m;}
#endif
#ifdef _DEBUG
#define DEBUG_CLIENTBLOCK new( _CLIENT_BLOCK, __FILE__, __LINE__)
#else
#define DEBUG_CLIENTBLOCK
#endif
#define _CRTDBG_MAP_ALLOC
#include
#ifdef _DEBUG
#define new DEBUG_CLIENTBLOCK
#endif
#endif
#endif _UT_DETECT_MEMLEAK_H
DebugCodeCRT(
_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF););
int main(int argc, char* argv[])
{
DebugCodeCRT(
_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF););
char* p = new char();
char* pp = new char[10];
char* ppp = (char*)malloc(10);
return 0;
}
要在Dumpint objects -> 后面产生文件名的话来确定 泄露文件与代码行号的话(见上面红字部分)则需要在
#include
#define _CRTDBG_MAP_ALLOC
#include //msdn里面的例子加了该头文件
#include
11 在什么时候调用_crtdumpmemoryleak?
发现有的时候像dllmain这样的出口函数位置不准确会导致一堆问题,误报许多memory leak.
可以使用atexit 将此函数注册在exit()上
代码如下
写一个函数
void Exit()
{
int i = _CrtDumpMemoryLeaks();
}
例如Dllmain
BOOL APIENTRY DllMain(HMODULE hModule,
DWORD fdwReason,
LPVOID lpReserved
)
{
switch (fdwReason)
{
case DLL_PROCESS_ATTACH:
//Create the testlog instance
DebugCode(
UT_TestLog::GetInstance()->printlnlogA("Init the ATSWord control");
atexit(Exit);
);