Conventional means for detecting memory leaks: Debugnew

xiaoxiao2021-03-06  42

Tools for detecting memory: DebugNew online has a wide range of detection memory leaks: Debugnew (Debugnew.h / debugnew.cpp) usage is simple, put debugnew.cpp, compile together, need to detect files Debugnew.h is in front of the file. For convenience, some small changes have been made to the source code. Here are some simple descriptions:

1, NEW's heavy-duty VOID * OPERATOR New (size_t size, const char * file, int line); (1 )void * operator new [] (size_t size, const char * file, int line); (2)

Redefine new # define new new new new new (__) in the file that needs to be detected.

Resulting: classname * p = new className; => classname * p = new (__ file__, __line__) classname; // actually call VOID * OPERATOR New (size_t size, const char * file, int line);

ClassName ** pp = new classname [count]; => classname ** pp = new (__ file__, __line__) classname [count]; // actually call void * operator new [] (size_t size, const char * file, int line);

This actually uses the gracement new grammatical, through a simple macro, you can correspond to the corresponding overload (1), 2 2).

2, Delete's heavy-duty Void Operator delete (void * p, const char * file, int line); (4) void operator delete [] (void * p, const char * file, int line); ⑷void operator delete (void * p) ⑸void operator delete [] (void * p); ⑹

Because there is no syntax similar to the Placement New, you can't replace DELETE with a macro. To call the DELETE operator with more information, you can only modify the source code. Delete p; => delete (p, __file__, __line__); delete [] pp; => delete [] (pp, __file__, __line__); but this work is very cumbersome, if you don't need extra information, you will be simply heavy It can be used in Delete.

3, when the detection and statistical procedure starts, a DebugNewTracer object will create a debugnewtracer object in the heavy-duty New Operator ((1), 2), each memory allocation will be recorded, and in Delete ((3), ⑷, ⑸ The corresponding record will be deleted in the ⑹). When the program ends, the Debugnewtracer object is destroyed, and its destructive function will dump remaining records, which is the sluggish memory.

On the basis of the original code, the function of the record size is added so that you can see the actual memory when each time new and delete. All information can be dump, or write log. 4. Use DebugneWMFC in the MFC project to provide a good support for check memory, in general, when adding a CPP file in the MFC project, the MFC will automatically add the following code:

#ifdef _debug # undef this_filestatic char this_file [] = __ file __; # Define new debug_new # Endif

At this time, I don't use our own debugnew.

Now, you have an MFC project, and there is a non-MFC C project, and the MFC project will reference the algorithm provided by the C project.

Now, you have an MFC project, and there is a non-MFC C project, and the MFC project will reference the algorithm provided by the C project.

The usual approach is to compile the C project into one *, lib, then link with the MFC project.

Then there is a problem:

The MFC can detect memory leaks in the MFC project and give specific file names and line numbers. For C projects, although leaks can be detected, more information can not be given; if you join Debugnew in the C project, There will be an error.

Solution:

In C projects, don't join Debugnew, you can only quote Debugnew.h in the disclosed CPP file.

5, source code ********************************************************** ********** Debugnew.h:

/ * FileName: Debugnew.h this code is based on code retrieved from a web site. The Author Was Not Identified, So Thanks Go To Anonymous.

THIS Used to Substitution a Version of The New Operator That Can Be Used for Debugging Memory Leaks. To Use it: - in any (all?) Code files #include debugnew.h. Make Sure All System Files (IE Those in <> 's) are #included before debugnew.h, and that any header files for your own code are #included after debugnew.h. The reason is that some system files refer to :: new, and this will not compile if debugnew is in . effect You may still have problems if any of your own code refers to :: new, or if any of your own files #include system files that use :: new and which have not already been #included before debugnew.h -. Add debugnew.cpp to the CodeWarrior project or compile it into your Linux executable. If debugnew.cpp is in the project, then debugnew.h must be #included in at least one source file * / # ifndef __DEBUGNEW_H __ # define __DEBUGNEW_H__

#include

#define log_file

#if Defined (log_file) #define log_file_name "./debugnew.log"#Dif

Void * operator new (std :: size_t size, const char * file, int line); void Operator delete (void * p, const char * name, int line); void * operator new [] (std :: size_t size, Const char * file, int line; void Operator delete [] (Void * P, const char * name, int line);

Class debugnewtracer {private: entry (char const * file, int line): _file (file), _Line (line) {} entry (char const * file, int line, int size): _file (file) _Line (line), _Size (size) {} entry (): _file (0), _LINE (0), _Size (0) {} const char * file () const {return _file;} int line () const { Return _line;} size_t size () const {return _size;} private: char const * _file; int _line; size_t _size;};

class Lock {public: Lock (DebugNewTracer & DebugNewTracer): _DebugNewTracer (DebugNewTracer) {_DebugNewTracer.lock ();} ~ Lock () {_DebugNewTracer.unlock ();} private: DebugNewTracer & _DebugNewTracer;}; typedef std :: map < void *, entry> :: item debugnewtracer (); ~ debugnewtracer (); void add (void * p, const char * file, int line); void add (void * p, const char * file, int line, size_t size); Void Remove (Void * P); void dump (); static bool ready;

PRIVATE: VOID LOCK () {_lockcount ;} void unlock () {_lockcount--;

Private:

Std :: map _map; int _lockcount; size_t _totalsize; #if defined (log_file) file * _logfp; #ENDIF};

.. // The file that implements class DebugNewTracer // does NOT want the word "new" expanded // The object DebugNewTrace is defined in that // implementation file but only declared in any other file # ifdef DEBUGNEW_CPPDebugNewTracer DebugNewTrace; # else # define New new (__ file__, __line __) extern debugnewtracer debugnewtrace; #ENDIF

#ENDIF / / # IFNDEF __DEBUGNEW_H__

*********************************************************** ****** Debugnew.cpp:

/ * Filename: debugnew.cpp

This is used to substitution a Version of the New Operator That Can Be Used for Debugging Memory Leaks. In any (all?) Code files #include debugnew.h. Add debugnew.cpp to the project. * /

#include #include

Using namespace std;

// this disables macro expansion of "new". // this statement should Only Appear in this file. # Define debugnew_cpppp

#include "debugnew.h"

Debugnewtracer :: Debugnewtracer (): _lockcount (0) {// Once this Object is constructed all calls to // new stay be traced.

Ready = true; _Totalsize = 0; #if defined (_Logfp = fopen ("log_file_name," wt ")) == NULL) {Printf (" Error! File: debugnew.log can not open @! / N "); Return;} fprintf (_logfp," new, delete list: / n "); fflush (_logfp); # Endif} void debugnewtracer :: add (void * p, const char * file, int line) {//// Tracing must not be done a second time // while it is already // in the middle of executing if (_lockCount> 0) return; // Tracing must be disabled while the map // is in use in case it calls new DebugNewTracer. :: Lock Lock (* this); _MAP [P] = entry (file, line);

Void Debugnewtracher :: Add (void * p, const char * file, int line, size_t size) {// trapeng must not be done a second Time // While it is already // in the middle of exec ▪ f (_lockcount> 0 Return;

// Tracing Must Be Disabled While The Map // IS in Use in Case It Calls New. Debugnewtracer :: Lock Lock (* this); # if 1 // 'ó «â 3/4¶ööìáè ¡ Î äþþþþ // linuxïâμägcc, __ file__1/1/1/1 £ ¨Windowsïμμþþûû «Windowsïμμävc, __ file__ ° üà ¨ «â 3/4¶, ëùòô fõõññμμμ' (File, '//') == NULL? File: Strrchr (file, '//') 1; #ENDIF _MAP [P] = entry (file, line, size); _totalsize = size; #if defined (log_file) fprintf (_logfp, "* n p = 0x% 08x, size = % 6D,% -22S, Line:% 4D. Totalsize =% 8D / N ", P, Size, File, Line, _Totalsize; FFlush (_Logfp); # Endif}

Void Debugnewtracher :: remove (void * p) {// Tracing Must not be done a second time // while it is already // in the middle of executingiffiffiff;

// Tracing Must Be Disabled While The Map // Is in Use in Case It Calls New. Debugnewtracer :: Lock Lock (* This);

Iterator it = _map.find (p);

IF (it! = _Map.end ()) {size_t size = (* it). Second.size (); _totalsize - = size; #if defined (log_file) fprintf (_logfp, "# d P = 0x% 08X, Size =% 6u.% 39stotalsize =% 8D / N ", P, Size," ---------------------------------------------------------------------------------------------------------------------- ---- ", _Totalsize); fflush (_logfp); # endif _map.ed (it);} else {#if defined (log_file) fprintf (_logfp," # d P = 0x% 08X. Error Point !! / n ", p); fflush (_logfp); # endif}} debugnewtracer :: ~ debugnewtracer () {// trace must not be caled if dump indirectly // invokes new, so it must be disabled before // dump is called After this destructor executes // Any Other Global Objects That Get Destructed // Should Not Do Any Tracing. Ready = false; dump (); # if defined (log_file) fclose (_logfp); # ENDIF}

// if Some Global Object Is Destructed After Debugnewtracer // and if this Object Calls New, It Should Not Trace That // Call To new.void debugnewtracer :: dump () {i (_map.size ()! = 0) { Std :: cout << _map.size () << "Memory Leaks Detected / N"; # if defined (log_file) fprintf (_logfp, "/ n / n ***% d Memory Leaks detected / n", _map. Size ()); fflush (_logfp); # Endif for (item it = _map.begin (); it! = _map.end (); it) {char const * file = it-> second.file () ; Int line = it-> second.line (); int size = it-> second.size (); std :: cout << file << "," << line << std :: endl; #if Defined (Log_file) FPRINTF (_Logfp, "% S,% D, size =% d / n", file, line, size); fflush (_logfp); # Endif}} else {std :: cout << "no Leaks detected / N "; # if defined (log_file) fprintf (_logfp," no leaks detected / n "); fflush (_logfp); # endif}

}

// If some global object is constructed before DebugNewTracer // and if that object calls new, it should not trace that // call to new.bool DebugNewTracer :: Ready = false; void * operator new (size_t size, const char * file , int line) {void * p = malloc (size); IF (debugnewtracer :: ready) debugnewtrace.add (p, file, line, size); return p;}

Void Operator Delete (Void * p, const char * file, int line) {file = 0; // avoid a warning about argument not buy in function line = 0; // Avoid a Warning About Argument Not Used in Function IF (Debugnewtracer :: ready) Debugnewtrace.Remove (P); Free (p);} void * Operator new [] (size_t size, const char * file, int line) {void * p = malloc (size); if (debugnewtracer :: Ready) Debugnewtrace.Add (p, file, line, size); Return P;

Void operator delete [] (void * p, const char * file, int line) {file = 0; // avoid A Warning About argument not buy in function line = 0; // avoid a warning about argument not buy in function IF (Debugnewtracer :: Ready) Debugnewtrace.Remove (P); Free (p);} void * Operator new (size_t size) {void * p = malloc (size); // When Uncommented these Lines Cause Entries in the map for calls to new // that were not altered to the debugnew version. These are likely calls // in library functions and the presence in the dump of these entries // is usually misleading. // if (DebugNewTracer :: Ready) // DebugNewTrace. Add (p, "?", 0); return p;} void operator delete (void * p) {if (debugnewtracer :: ready) debugnewtrace.remove (p); free (p);}

// add by yugangvoid operator delete [] (void * p) {if (debugnewtracer :: ready) debugnewtrace.remove (p); free (p);}

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

New Post(0)