How to detect memory leaks - overload New and Delete

xiaoxiao2021-03-06  56

Copyright statement

This article can be freered, but must follow the following copyright agreement:

1. Keep this convention and retain the beginning of the article.

2, you cannot modify the article content, or apply, increase. If you think that this article needs to be modified, please

Contact the author.

3. You cannot extract the contents of this article, you must publish or quote full text.

4. The author must retain the author's signature, indicate the source of the article. (This article is authorized to www.linuxaid.com.cn)

5. If you do not follow this regulation, you have no need to reprint this article.

Author

Ariesram

email address

Ariesram@linuxaid.com.cn, or ariesram@may10.ca

All of this article and all the articles are collected in Bambi.May10.ca/~ariesram/Articles/.

This article authorizes to www.linuxaid.com.cn.

text:

I have participated in a relatively large project. In this project, we don't have a fully determined design document, so the implementation of the program often changes. Although we have a more flexible framework, it makes our program very chaotic from the perspective of the program. Until the date of the release is approaching, we have no stable version that can be used to do alpha tests. So we must delete the useless code as soon as possible, so that this version is sufficiently stable. However, in this software company that is not enough standard, we don't have enough efforts to do your border testing. So we can only use a variety of ways. The biggest problem in the software is memory leakage. Because of this situation, we allocated memory in a code, but they did not release it. This has caused a big problem. We need a simple solution that can be easily compiled into this project. When it is running, it can generate a list of memory that is not released, with this list, we can correct the program's error. This is how we call it memory tracking. First, we need a code that can be added to the source code, and this code can be reused. Code reuse is a very important feature that saves a lot of time and money and programmers. In addition, our code must be simple because we have not so much time and energy to completely focus on all the code to rewrite and correct the error to make memory tracking.

Ok, we can always find solutions. First, we checked the code and found that all the code used New to allocate memory, with Delete to release memory. So, can we replace it with a full range of New and DELETE operators? No. Because the size of the code is too big, there is no such thing as waste time. Fortunately, our source code is written with C , so this means that there is no need to replace all new and delete, but only overload the two operators. By the way, the value is overloaded with these two operators, we can do something before distribution and release memory. This is an absolute good news. We also know how to do it. Because the MFC is also doing this. What we need to do is to track all memory allocation and interaction references and memory release. Our source code uses Visual C to write, of course, this solution can also be easily used in other C code. The first thing to do is overloading the New and Delete operators, which will be used in all the code. We are joined in stdafx.h.

#ifdef _Debug

Inline void * __cdecl operator new (unsigned int size,

Const char * file, int line)

{

}

Inline void __cdecl operator delete (void * p) {

}

#ENDIF

In this way, we overload New and Delete operators. We wrap the two overload operators with $ IFDEF and #ENDIF, so that the two operators will not appear in the release. Take a look at this code, it will find that there are three parameters of the New operator, they are allocated memory sizes, the file names, and the line number. This is necessary for finding memory leaks. Otherwise, you will take a lot of time to find the exact places they appear. Add this code, our call new () code is still pointing to the NEW operator that only accepts one parameter, not this an operator that accepts three parameters. In addition, we don't want to record all the statements of all new operators to contain __file__ and __line___ parameters. What we need to do is Auto let all NEW operators that accept a parameter to call the new operator that accepts three parameters. This can be done with a little small skill, such as the following paragraph of macro,

#ifdef _Debug

#define debug_new new (__ file__, __line__)

#ELSE

#define debug_new new

#ENDIF

#define new debug_new

Now all of our NEW operators that accept a parameter have become New operation symbols accepted three parameters, __ file__ and __line__ are automatically inserted by the precompiler. Then, it is actually tracked. We need to add some routines to our overloaded functions to make them complete allocation of memory and release memory. Do this, #ifdef _debug

Inline void * __cdecl operator new (unsigned int size,

Const char * file, int line)

{

Void * ptr = (void *) malloc (size);

AddTrack ((DWORD) PTR, SIZE, FILE, LINE

Return (PTR);

}

Inline void __cdecl operator delete (void * p)

{

RemoveTrack (DWORD) P);

Free (p);

}

#ENDIF

In addition, the same method needs to be used to overrun the New [] and Delete [] operators. This is omitted here.

Finally, we need to provide a set of functions addTrack () and removeTrack (). I use STL to maintain the connection table for storing memory allocation records.

These two functions are as follows:

Typedef struct {

DWord Address;

DWORD size;

Char file [64];

DWORD line;

ALLOC_INFO;

TYPEDEF LIST alloclist;

Alloclist * alloclist;

Void AddTrack (DWORD ADDR, DWORD Asize, Const Char * FNAME, DWORD LNUM)

{

ALLOC_INFO * INFO;

IF (! alloclist) {

Alloclist = New (alloclist);

}

INFO = New (alloc_info);

Info-> address = addr;

STRNCPY (Info-> File, FNAME, 63);

Info-> line = lnum;

INFO-> SIZE = asize;

Alloclist-> INSERT (alloclist-> begin (), info);

}

Void RemoveTrack (DWORD ADDR)

{

Alloclist :: Iterator i;

IF (! alloclist)

Return;

For (i = alloclist-> begin (); i! = alloclist-> end (); i )

{

IF ((* i) -> address == addr)

{

Alloclist-> remove ((* i));

Break;

}

}

}

Now, before our program exits, alloclist stores memory allocation that is not released. In order to see what they are and where they are allocated, we need to print data from alloclist. I used the Output window in Visual C to do this.

void dumpunfreed ()

{

Alloclist :: Iterator i;

DWORD TOTALSIZE = 0;

Char BUF [1024];

IF (! alloclist)

Return;

For (i = alloclist-> begin (); i! = alloclist-> end (); i ) {

Sprintf (buf, "% -50s: line% d, address% D% D unfreed",

(* i) -> file, (* i) -> line, (* i) -> address, (* i) -> size);

OutputDebugstring (buf);

TOTALSIZE = (* i) -> size;

}

Sprintf (BUF, "---------------------------------------------------------------------------------------------------------------------- -------------- ");

OutputDebugstring (buf);

Sprintf (BUF, "Total Unfreed:% D Bytes", TOTALSIZE

OutputDebugstring (buf);

}

Now we have a reusable code to monitor all memory leaks. This code can be used to join all items. Although it doesn't make your program look better, but at least it can help you check the error and make the program more stable.

转载请注明原文地址:https://www.9cbs.com/read-115518.html

New Post(0)