• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            春暖花開
            雪化了,花開了,春天來(lái)了
            posts - 149,comments - 125,trackbacks - 0
             

            檢測(cè)內(nèi)存泄露的工具:debugnew
            http://dev.csdn.net/article/58/58407.shtm

            網(wǎng)上有一個(gè)流傳甚廣的檢測(cè)內(nèi)存泄露的工具:debugnew(debugnew.h/debugnew.cpp)
            用法很簡(jiǎn)單,把debugnew.cpp放在項(xiàng)目里一起編譯,需要檢測(cè)的文件把debugnew.h嵌在文件的最前面。

            為方便使用,對(duì)源代碼做了一些小的改動(dòng)。

            下面是一些簡(jiǎn)單的說(shuō)明:

            1、new 的重載
            void* operator new (size_t size, const char* file, int line);        ⑴
            void* operator new [] (size_t size, const char*  file, int line);      ⑵

            在需要檢測(cè)的文件里,重定義new
            #define new new(__FILE__, __LINE__)

            造成的結(jié)果:
            ClassName *p = new ClassName; => ClassName *p = new(__FILE__, __LINE__) ClassName;
            // 實(shí)際會(huì)調(diào)用void* operator new (size_t size, const char* file, int line);

            ClassName **pp = new classname[count]; => ClassName **pp = new(__FILE__, __LINE__) ClassName[count];
            // 實(shí)際會(huì)調(diào)用void* operator new [] (size_t size, const char*  file, int line);

            這其實(shí)是利用了placement new的語(yǔ)法,通過(guò)一個(gè)簡(jiǎn)單的宏,就可以把普通的new操作對(duì)應(yīng)到相應(yīng)的重載( ⑴,⑵ )上去。

            2、delete 的重載
            void operator delete (void* p, const char* file, int line);                   ⑶
            void operator delete [] (void* p, const char* file, int line);                ⑷
            void operator delete (void* p);                                               ⑸
            void operator delete [] (void* p);                                            ⑹

            因?yàn)闆]有類似于placement new的語(yǔ)法,所以就不能用一個(gè)宏來(lái)替換替換delete了。要調(diào)用帶有更多信息的delete操作符,只能修改源代碼了。
            delete p; => delete ( p, __FILE__, __LINE__ );
            delete []pp; => delete [] ( pp, __FILE__, __LINE__ );
            但這個(gè)工作很煩瑣,如果并不需要多余的信息的話,簡(jiǎn)單地重載delete( ⑸,⑹ )就可以了。

            3、檢測(cè)和統(tǒng)計(jì)
            程序開始時(shí),在debugnew.cpp中會(huì)創(chuàng)建一個(gè)DebugNewTracer對(duì)象
            在重載的new操作符( ⑴,⑵ )中,每一次內(nèi)存分配都會(huì)被記錄,而在delete( ⑶,⑷,⑸,⑹ )中則會(huì)刪除相應(yīng)的記錄。
            當(dāng)程序結(jié)束,DebugNewTracer對(duì)象被銷毀,它的析構(gòu)函數(shù)會(huì)dump剩余的記錄,這就是泄露的內(nèi)存了。

            在原有代碼的基礎(chǔ)上,增加了記錄size的功能,這樣可以在每次new和delete時(shí),看到實(shí)際占用的內(nèi)存。所有信息可以dump出來(lái),也可以寫入log。


            5、源代碼

            ********************************************************
            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 is used to substitute 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 (i.e. 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 <map>

            #define LOG_FILE

            #if defined(LOG_FILE)
            #define LOG_FILE_NAME "./debugnew.log"
            #endif

            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:
             
             class Entry  {
             public:
              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>::iterator iterator;
             friend class Lock;
             public:
             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<void*, Entry> _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_CPP
            DebugNewTracer DebugNewTrace;
            #else
            #define new new(__FILE__, __LINE__)
            extern DebugNewTracer DebugNewTrace;
            #endif

            #endif//#ifndef __DEBUGNEW_H__


            ********************************************************
            debugnew.cpp:

            /*
             filename: debugnew.cpp

             This is used to substitute 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 <iostream>
            #include <map>

            using namespace std;

             // This disables macro expansion of "new".
             // This statement should only appear in this file.
            #define DEBUGNEW_CPP

            #include "debugnew.h"

            DebugNewTracer::DebugNewTracer () : _lockCount (0)
            {
              // Once this object is constructed all calls to
              // new should be traced.

             Ready = true;
             _totalsize = 0;
            #if defined(LOG_FILE)
             if( (_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 DebugNewTracer::Add (void* p, const char* file, int line, size_t size)
            {
             // 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);
            #if 1
             //´Óȫ·¾¶ÖÐÌáÈ¡ÎļþÃû
             //linuxϵÄgcc,__FILE__½ö½ö°üÀ¨ÎļþÃû£¬windowsϵÄvc,__FILE__°üÀ¨È«Â·¾¶,ËùÒÔÓÐÕâÑùµÄ´¦Àí
             file = strrchr(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 DebugNewTracer::Remove (void* p)
            {
             // 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);

             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.erase (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 called 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 that object calls new, it should not trace that
            // call to new.
            void DebugNewTracer::Dump ()
            {
             if (_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 (iterator 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 used 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 used 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)
            {
             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 yugang
            void operator delete [] (void* p)
            {
             if (DebugNewTracer::Ready)
              DebugNewTrace.Remove (p);
             free (p);
            }

            posted on 2008-11-02 10:52 Sandy 閱讀(730) 評(píng)論(0)  編輯 收藏 引用 所屬分類: C++
            国产亚洲精品久久久久秋霞| 久久久久亚洲精品男人的天堂 | 国内精品伊人久久久久| 区久久AAA片69亚洲| 合区精品久久久中文字幕一区 | 亚洲欧洲日产国码无码久久99| 久久精品国产精品亚洲人人| 天天爽天天爽天天片a久久网| 91精品国产91久久久久福利| 99国产欧美久久久精品蜜芽| 996久久国产精品线观看| 久久久久国产精品| 精品久久久久国产免费| 亚洲а∨天堂久久精品9966| 国内精品伊人久久久影院| 久久精品国产99国产精品导航 | 欧美午夜A∨大片久久| 午夜视频久久久久一区 | 久久精品国产精品亜洲毛片| 久久免费大片| 色欲av伊人久久大香线蕉影院| 无码人妻精品一区二区三区久久| 国产亚洲婷婷香蕉久久精品| 狠狠精品干练久久久无码中文字幕 | 久久亚洲欧美日本精品| 青青青青久久精品国产h久久精品五福影院1421 | 天堂无码久久综合东京热| 亚洲国产精品无码久久九九| 久久这里只有精品18| 伊人久久大香线焦综合四虎| 久久久午夜精品| 久久精品国产99国产精品澳门 | 久久e热在这里只有国产中文精品99| 中文国产成人精品久久亚洲精品AⅤ无码精品| 婷婷国产天堂久久综合五月| 久久91精品久久91综合| 亚洲国产日韩欧美综合久久| 久久亚洲综合色一区二区三区| 久久人人爽人人爽人人片AV不| 午夜不卡888久久| 久久久精品人妻一区二区三区蜜桃|