Although this concept has been widely used, I still want to record it for future queries.
Copy codeThe Code is as follows: # ifdef _ DEBUG
# Define DEBUG_CLIENTBLOCK new (_ CLIENT_BLOCK, _ FILE __, _ LINE __)
# Else
# Define DEBUG_CLIENTBLOCK
# Endif
# Define _ CRTDBG_MAP_ALLOC
# Include <crtdbg. h>
# Ifdef _ DEBUG
# Define new DEBUG_CLIENTBLOCK
# Endif
Int _ tmain (int argc, _ TCHAR * argv [])
{
Char * p = new char ();
Char * pp = new char [10];
Char * ppp = (char *) malloc (10 );
_ CrtDumpMemoryLeaks ();
Return 0;
}
The main principle is to use the Crt memory debugging function and use macros to replace the default operator new so that it is replaced by the following versions:Copy codeThe Code is as follows: void * _ CRTDECL operator new (
Size_t cb,
Int nBlockUse,
Const char * szFileName,
Int nLine
)
_ THROW1 (_ STD bad_alloc)
{
/* _ Nh_malloc_dbg already call_heap_alloc_dbg in a loop and call_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;
}
In this way, the Crt will record the file name, row number, and size of the allocated memory. When _ CrtDumpMemoryLeaks () is called, it will be printed if it has not been released.
The result is as follows:Copy codeThe Code is as follows: Detected memory leaks!
Dumping objects->
F: \ test \ memleakchecker. cpp (23): {108} normal block at 0x0003A1A8, 10 bytes long.
Data: <> CD
F: \ test \ memleakchecker. cpp (22): {107} client block at 0x0003A160, subtype 0, 10 bytes long.
Data: <> CD
F: \ test \ memleakchecker. cpp (21): {106} client block at 0x0003A120, subtype 0, 1 bytes long.
Data: <> 00
Object dump complete.
The following are some notes:
(1) # functions of define _ CRTDBG_MAP_ALLOC
If this macro is not defined, the malloc leakage in C mode will not be recorded.
(2) functions of number {108} {107}
Indicates the number of times allocated. You can use _ CrtSetBreakAlloc to suspend the program for a specified number of times, such
Copy codeThe Code is as follows: int _ tmain (int argc, _ TCHAR * argv [])
{
_ CrtSetBreakAlloc (108 );
Char * p = new char ();
Char * pp = new char [10];
Char * ppp = (char *) malloc (10 );
_ CrtDumpMemoryLeaks ();
Return 0;
}
(3) If the program has multiple egresses or involves global variables, you can use _ CrtSetDbgFlag to set the flag so that the program will automatically print out when exiting, for exampleCopy codeThe Code is as follows: int _ tmain (int argc, _ TCHAR * 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;
}
(4) We know that macro substitution is the most crude method, so try to put the new substitution macro below into every Cpp instead of a general header file. In fact, this is what MFC does.Copy codeThe Code is as follows: # ifdef _ DEBUG
# Define new DEBUG_CLIENTBLOCK
# Endif
(5) The above operator new can only take care of the most common new. In fact, operator new has any number of overload methods. You only need to ensure that the first parameter represents the size. For example, the following placement new will fail to be compiled, because the format after macro replacement does not meet the requirements, so if your CPP uses a non-standard new, do not add the new macro detection.Copy codeThe Code is as follows: # include <new>
# Ifdef _ DEBUG
# Define DEBUG_CLIENTBLOCK new (_ CLIENT_BLOCK, _ FILE __, _ LINE __)
# Else
# Define DEBUG_CLIENTBLOCK
# Endif
# Define _ CRTDBG_MAP_ALLOC
# Include <crtdbg. h>
# Ifdef _ DEBUG
# Define new DEBUG_CLIENTBLOCK
# Endif
Int _ tmain (int argc, _ TCHAR * 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;
}
(6) because the tree in map in STL uses placement new, if you use it like this, compilation will fail:Copy codeThe Code is as follows: # ifdef _ DEBUG
# Define DEBUG_CLIENTBLOCK new (_ CLIENT_BLOCK, _ FILE __, _ LINE __)
# Else
# Define DEBUG_CLIENTBLOCK
# Endif
# Define _ CRTDBG_MAP_ALLOC
# Include <crtdbg. h>
# Ifdef _ DEBUG
# Define new DEBUG_CLIENTBLOCK
# Endif
# Include <map>
You should put # include <map> in front of the macro definition.
(7) If you declare or define the operator new function after the macro # define new DEBUG_CLIENTBLOCK, compilation will fail because of macro substitution.
The xdebug file of STL just declares the operator new function. Therefore, ensure that the new substitution macro is placed at the end of all include header files, especially after the STL header files.
Copy codeThe Code is as follows: // MyClass. cpp
# Include "myclass. h"
# Include <map>
# Include <algorithm>
# Ifdef _ DEBUG
# Define new DEBUG_CLIENTBLOCK
# Endif
MyClass: MyClass ()
{
Char * p = new char ('A ');
}
(8) If you think it is too troublesome to place the new substitution macro in each CPP and want to put everything in a general header file, refer to the method defined below:Copy codeThe Code is as follows: // MemLeakChecker. h
# Include <map>
# Include <algorithm>
// Other STL file
# Ifdef _ DEBUG
# Define DEBUG_CLIENTBLOCK new (_ CLIENT_BLOCK, _ FILE __, _ LINE __)
# Else
# Define DEBUG_CLIENTBLOCK
# Endif
# Define _ CRTDBG_MAP_ALLOC
# Include <crtdbg. h>
# Ifdef _ DEBUG
# Define new DEBUG_CLIENTBLOCK
# Endif
(9) the following method can be used to determine whether an independent function has memory leakage:Copy codeThe Code is as follows: 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;
{
Char * p = new char ();
Char * pp = new char [10];
Char * ppp = (char *) malloc (10 );
}
Return 0;
}
(10) Actually, it is not difficult to write a set of C ++ Memory leakage detection by yourself, mainly by reloading operator new and operator delete, you can record each memory allocation in a Map, delete the record during the delete operation, and print the records without the delete operation in the map when the program exits. Of course, we know that when the Crt implements new, it generally calls malloc, while malloc may call HeapAlloc, while HeapAlloc may call RtlAllocateHeap, so theoretically, we can intercept and record at any layer of these functions. But if you want to implement your own cross-platform Memory Leak Detection, reload operator new.