Detecting memory leaks: The key to detect memory leaks is to capture the call to the allocated memory and release of the memory. Intercept these two functions, we can track the life cycle of each memory, for example, after the successful assignment of memory, add its pointer to a global list; whenever you release a memory, then put it The pointer is removed from the list. Thus, when the program ends, the remaining pointers in the List are pointing to those that are not released. Here is just a simple description of the basic principle of detecting memory leaks, detailed algorithms can see Steve MAGUIRE <
".
If you want to detect the leak of the stack, you can intercept Malloc / Realloc / Free and New / Delete can be used (in fact new / delete ultimately using Malloc / Free, so as long as you intercepting a group). For other leaks, a similar approach can be used to capture the corresponding allocation and release functions. For example, to detect the leak of BSTR, you need to intercept Sysallocstring / Sysfreestring; to detect HMENU leaks, you need to intercept CreateMenu / DestroyMenu. (Some resource allocation functions have multiple, the release function is only one, for example, SysallocStringlen can also be used to assign BSTR, and then intercept multiple allocation functions)
Under the Windows platform, the tools that detect memory leaks are commonly used, MS C-Runtime Library built-in detection function; plunched detection tool, such as Purify, BoundSchecker, etc .; Performance Monitor that comes with Windows NT. The three tools have advantages and disadvantages, although the MS C-Runtime Library is functionally weak, but it is free; Performance Monitor does not indicate the code of the problem, but it can detect implicit The existence of memory leaks, this is where two other types of tools are unable to force.
Here we discuss these three test tools in detail:
Detection method of memory leak under VC
Using the application developed by MFC, after compiling in the Debug mode, the detection code of the memory leak will be automatically added. After the end of the program, if a memory leak occurs, all the information of all the leaks occurred in the Debug window, the following two lines show information of a leakful memory block:
E: /TESTMEMLEAK/Testdlg.cpp (70): {59} Normal Block AT 0x00881710, 200 BYTES Long.
Data:
61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70
The first line shows that the memory block is allocated by the TestDlg.cpp file, the 70r-line code, the address is 0x0081710, the size is 200 bytes, and {59} refers to the request order of the memory allocation function. For more information about it, see MSDN Help in _CRTSetBreakalloc (). The second line shows the contents of the 16 bytes of the memory block, and the angle brackets are displayed in an ASCII mode, followed by a 16-way method.
Generally, everyone is mistaken to think that the detection function of these memory leaks is provided by the MFC, which is not. The MFC is only packaged and utilized with the Debug Function of MS C-Runtime Library. Non-MFC programs can also use the Debug Function of MS C-Runtime Library to join memory leak detection. MS C-Runtime Library has built a memory leak detection function when implementing functions such as Malloc / Free, StrDUP. Note Observe the project generated by the MFC Application Wizard, there is such a macro definition at the head of each CPP file:
#ifdef _Debug
#define new debug_new
#undef this_file
Static char this_file [] = __file__;
#ENDIF
With this definition, when compiling the Debug version, all NEWs in this CPP file are replaced into debug_new. So what is debug_new? Debug_new is also a macro, here is taken from Afx.h, 1632 lines
#define debug_new new (this_file, __LINE__)
So if there is such a line of code:
Char * p = new char [200];
After the macro replacement becomes:
CHAR * P = New (this_file, __line __) char [200];
According to C standards, for the above New's method, the compiler will find this defined Operator New:
Void * Operator New (size_t, lpcstr, int)
We found a so Operator new implementation in AfxMem.cpp 63 lines.
Void * AFX_CDECL Operator New (size_t nsize, lpcstr lpszfilename, int nline)
{
Return :: Operator New (nsize, _normal_block, lpszfilename, nline);
}
Void * __cdecl operator new (size_t nsize, int NTYPE, LPCSTR LPSZFILENAME, INT NLINE)
{
...
PRESULT = _malloc_dbg (nsize, ntype, lpszfilename, nline);
IF (PRESULT! = NULL)
Return PRESULT;
...
}
The second Operator New function is relatively long. For the sake of simplicity, I only extracted the part. Obviously the last memory distribution is also implemented through the _malloc_dbg function, this function belongs to the debug function of MS C-Runtime Library. This function not only requires the size of the memory, but also two parameters of the file name and the line number. The file name and the line number are used to record which code caused by this assignment. If there is no release before the program ends, then this information will be output to the Debug window.
Here, this_file, __ file and __line__ are encompasced here. __File__ and __line__ are all macros defined by the compiler. When it comes to __file__, the compiler will replace __file__ to replace it with a string, which is the path name of the current compiled file. When it comes to __line__, the compiler will replace __line__ to a number, this number is the line number of the current line code. In the definition of debug_new, it is not directly used in __file__, but used this_file, the purpose is to reduce the size of the target file. Assuming that there is 100 in a CPP file, if you use __file__ directly, the compiler generates 100 constant strings, which is the path name of this CPP file, which is clearly very redundant. If you use this_file, the compiler will only generate a constant string, and the 10 calls used by New are pointers that point to the constant string. Ob again observing the project generated by the MFC Application Wizard, we will find that only the NEW is only mapped in the CPP file. If you use the malloc function directly in the program, call Malloc's file name and the line number will not be recorded. of. If this memory has leaks, MS C-Runtime Library can still detect, but when the information of this memory block is output, the file name and line number allocated there is no.
It is very easy to open memory leak in non-MFC programs. You only need to add the following lines of code at the entrance of the program:
INT TMPFLAG = _CRTSETDBGFLAG (_CRTDBG_REPORT_FLAG);
TMPFLAG | = _CRTDBG_LEAK_CHECK_DF;
_CRTSETDBGFLAG (TMPFLAG);
In this way, after the end of the program, it is also after the WinMain, Main or DLLMAIN function returns, if there is still memory blocks, their information will be printed into the Debug window.
If you try to create a non-MFC application, add the above code at the entrance to the program, and deliberately do not release some memory blocks in the program, you will see the following information in the debug window:
{47} Normal Block AT 0x00c91c90, 200 Bytes long.
Data: <> 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
Memory leaks have indeed detected, but the file names and line numbers are missing compared to examples of the MFC program above. For a relatively large program, there is no such information, and the problem will become very difficult.
In order to be able to know where the leak memory block is allocated, you need to implement a mapping function similar to the MFC, map New, MAOLLOC and other functions to the _malloc_dbg function. Here I am not described again, you can refer to the source code of the MFC.
Since the debug function is implemented in the MS C-Runtimelibrary, it can only detect the leaks of the heap memory and is limited to the memory allocated by Malloc, Realloc or StrDUP, and those system resources, such as Handle, GDI Object, or not pass The memory allocated by C-Runtime Library, such as the leak of Variant, BSTR, which is impossible to detect, this is a major limitations of this test method. In addition, in order to record where the memory block is allocated, the source code must cooperate, which is very troublesome to debug some old procedures. After all, the source code is not a worries, this is another test method. A limiter. For developing a large program, the detection function provided by MS C-Runtime Library is far less than enough. Let's take a look at the external test tool. What is much more is BoundSchecker, one because it is more comprehensive, more important is its stability. Such tools are not stable, but will be busy with it. In the end, it is from the famous Numega, I have basically no big problem.