Collected and collated by www.169it.com
A memory leak is a common and frustrating problem for a C + + programmer. A number of techniques have been developed to address this problem, such as Smart pointer,garbage collection. Smart pointer technology is more mature, the STL already contains the class that supports smart pointer, but it doesn't seem to be widely used, and it doesn't solve all the problems; garbage collection technology is mature in Java, However, the development of the C + + field is not smooth, although it was early thought that in C + + also added GC support. The real world is like this, as a C + + programmer, memory leaks are the pain in your heart forever. Fortunately, however, there are many tools that can help us verify the existence of a memory leak and identify the code that has the problem.
1. Definition of memory leaks
void
MyFunction (
int
nSize)
{
Char
* P= 
new
char
[nSize];
if
(! Getstringfrom (P, nSize)) {
MessageBox ("Error");
return
;
}
...
//using The string pointed by P;
Delete
p;
}
When the function Getstringfrom () returns zero, the memory pointed to by the pointer P is not freed. This is a common scenario in which a memory leak occurs. The program allocates memory at the entrance, frees the memory at the exit, but the C function can exit anywhere, so a memory leak occurs whenever there is an exit where the memory that should be freed is not released.
Broadly speaking, memory leaks contain not only the leak of heap memory, but also the leakage of system resources (resource leak), such as nuclear mentality handle,gdi object,socket, interface, etc., fundamentally, these objects allocated by the operating system also consume memory, If these objects leak, they can eventually lead to memory leaks. Also, some objects consume kernel-mind memory, which can cause the entire operating system to become unstable when they are severely compromised. Therefore, the leakage of system resources is more serious than the leak of heap memory.
The disclosure of GDI object is a common resource leak:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
void CMyView::OnPaint( CDC* pDC ) { CBitmap bmp; CBitmap* pOldBmp; bmp.LoadBitmap(IDB_MYBMP); pOldBmp = pDC->SelectObject( &bmp ); … if ( Something() ){ return ; } pDC->SelectObject( pOldBmp ); return ; } |
When the function something () returns nonzero, the program does not select Poldbmp back to the PDC before exiting, which causes the Hbitmap object that poldbmp points to leak. If this program runs for a long time, it may cause the whole system to spend the screen. This problem is more easily exposed under Win9x, because the Win9x GDI heap is much smaller than Win2K or NT.
How a memory leak occurs:
In the way that happens, memory leaks can be categorized into 4 categories:
1) frequent memory leaks. The code that occurs in memory leaks is executed multiple times, causing a memory leak each time it is executed. For example two, if the something () function always returns True, the Hbitmap object that poldbmp points to always leaks.
2) Accidental memory leaks. Code that occurs with a memory leak occurs only under certain circumstances or during operation. For example two, if the Something () function returns True only in a specific environment, the Hbitmap object pointed to by Poldbmp does not always leak. The occurrence and the incidental sex are opposite. For a given environment, the occasional may become a frequent occurrence. So test environments and test methods are critical to detecting memory leaks.
3) disposable memory leaks. The code that occurs with a memory leak is only executed once, or because of an algorithmic flaw, there is always a piece of memory that leaks. For example, allocating memory in the class's constructor does not release the memory in the destructor, but because the class is a singleton, a memory leak only occurs once. Another example:
1 2 3 4 5 6 7 8 |
char * g_lpszFileName = NULL; void SetFileName( const char * lpcszFileName ) { if ( g_lpszFileName ){ free ( g_lpszFileName ); } g_lpszFileName = strdup( lpcszFileName ); } |
If the program does not release the string that G_lpszfilename points to at the end, even if you call Setfilename () multiple times, there will always be a piece of memory, and only one memory leaks.
4) An implicit memory leak. The program keeps allocating memory while it is running, but it does not release memory until the end. Strictly speaking, there is no memory leak, because the final program frees up all the requested memory. But for a server program that needs to run for days, weeks, or months, not releasing memory in time can also result in the eventual exhaustion of all of the system's memory. So, we call this kind of memory leak as an implicit memory leak. To give an example:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
class
Connection { public : Connection( SOCKET s); ~Connection(); … private : SOCKET _socket; … }; class
ConnectionManager { public : ConnectionManager(){} ~ConnectionManager(){ list::iterator it; for ( it = _connlist.begin(); it != _connlist.end(); ++it ){ delete
(*it); } _connlist.clear(); } void
OnClientConnected( SOCKET s ){ Connection* p = new
Connection(s); _connlist.push_back(p); } void
OnClientDisconnected( Connection* pconn ){ _connlist. remove ( pconn ); delete
pconn; } private : list _connlist; }; |
Assuming that the server does not call the onclientdisconnected () function after the client disconnects from the server, the connection object representing that connection will not be deleted in a timely manner (when the server program exits, All connection objects are deleted in the destructor of ConnectionManager). An implicit memory leak occurs when there are constant connections established and disconnected.
From the user's point of view of using the program, the memory leak itself does not have any harm, as a general user, there is no sense of memory leaks. What is really harmful is the accumulation of memory leaks, which eventually consumes all the memory of the system. From this point of view, a one-time memory leak is harmless, because it does not accumulate, and the implicit memory leak is very harmful because it is more difficult to detect than the usual and sporadic memory leaks.
2. Detecting Memory leaks
The key to detecting a memory leak is to be able to intercept calls to functions that allocate memory and free memory. Intercept these two functions, we can track the life cycle of each piece of memory, for example, each time a successful allocation of memory, the pointer is added to a global list, whenever a piece of memory is freed, and then its pointer is removed from the list. Thus, when the program finishes, the remaining pointers in the list are pointing to memory that is not freed. This is simply a simple description of the basic principle of detecting memory leaks, and the detailed algorithm can be found in the <<writing Solid code>> of Steve Maguire.
Under the Windows platform, there are three commonly used tools for detecting memory leaks, the MS c-runtime Library built-in detection function, external detection tools, such as Purify,boundschecker, etc., using Windows NT comes with the performance Monitor. Each of the three tools have advantages and disadvantages, MS C-runtime Library, although the function of the tool to be weaker than the plug-in, but it is free; Performance Monitor cannot identify the code that has the problem, but it can detect the existence of an implicit memory leak, This is where the other two types of tools are powerless.
Memory leaks are a big and complex problem, even in environments with Gabarge collection mechanisms such as Java and. NET, where leaks can occur, such as implicit memory leaks.
3. Avoid memory leaks
Write the server program, the most feared is the memory leaks. Because programs often run for months, a little memory leaks can cause tragedies. In general, the first is to avoid memory leaks, followed by checking for memory leaks.
1) No new
C + + programs, use STL as much as possible, avoid using new. The code I wrote myself, except for new in the main function, would not have any new occurrences anywhere else. This will give the memory management to STL to do.
Maybe you would say, "How is it possible without new?"
Very simply, the char array is replaced with std::string, and other objects are copied directly. Unless your object is large or large, a little copy is time-consuming and completely negligible.
2) Each important structure provides an info function
Add an info function to each of your important structures, and the info function returns a string that describes the state of the current structure, such as the size of the map and the size of the memory footprint. At the top level, the output of the timer (or output from the command) is the info result of each object. This avoids the invisible memory leak, which is not a memory leak, but an object keeps a reference to a large number of objects, causing the object to be deleted;
A map within an object, constantly adding data, is constantly deleting data, but in some special cases it is not deleted.
3) Problems with STL memory leaks
The STL has almost no memory leaks, but it has a memory cache that is friendly to the allocation of small objects. One of the problems with STL is that it will almost never release these spaces, so one result is that you see your program's memory consumption constantly rising. In fact, in theory is not afraid, because it rose to a certain extent (for example, the machine only hundreds of megabytes of usable space), it will not rise. You can use the export glibcxx_force_new=1 before running the program to let the STL do not cache. Note that this is only valid after GCC (g++) 3.3.
4) Valgrind and other memory detection tools
Download directly, compile (note that you must execute configure in the current directory of configure, cannot choose another directory), install. Execution: Valgrind--num-callers=20--leak-check=full--leak-resolution=high--show-reachable=yes--log-file=val.log xxx &, wait a few days, kill it, then slowly look at the Val.log file.
When you adopt the previous 3 strategies, Valgrind has little effect, anyway I never get any useful information from it. Mainly because the previous steps to ensure that there is no explicit memory leaks, so, Valgrind also can not find out what memory leaks.
5) Valgrind Tools massif
Massif better than Valgrind is that it tells you the current distribution of memory. You can see that the program that occupies hundreds of trillion is where the memory is occupied. Execution: Valgrind--tool=massif xxx. It is common to see significant memory leaks through this. This tool is very good, and I use it to find a very unusual situation, which is caused by the reserve of the vector. Should reserve the number of returned data, the result reserve the number of hit results. This causes the occasional memory consumption of 500M, but because there is no memory leak, so a few other tools can not be found, only massif provides a stack snapshot to find this problem.
Analysis and solution of memory leakage problem in C/C + + server program