Memory leak detector ( C++)

Memory leak detector ( C++)

This is a simple solution for memory leak detector.

For any C++ software source under windows, please follow these steps:


   1. You need to put MemoryTracker.h and MemoryAllocateTracker.h into include folder, and force all *.cpp file to include MemoryTracker.h first(when using MVS C++/Using precompiled headers, we usually include it within stdafx.h, and remove all MVS C++ generated DEBUG_NEW if exists);

   2. Besides, modify the log file location(which is now c:\temp\) in MemoryAllocateTracker.cpp, and rebuild the version of MemoryAllocateTracker.dll;

   3. Also make sure no other 'replace new' exists in your C++ source;

  
For any issues, please feel free to send email to health_163@163.com.

MemoryTracker.h

复制代码
   
   
#pragma once #ifdef _DEBUG #pragma comment(lib, "MemoryAllocateTracker.lib") #include " MemoryAllocateTracker.h " #ifdef new #undef new #endif inline void * __cdecl operator new (size_t size, const char * file, int line) { return MemoryAllocateTracker::GetInstance().re_malloc_dbg(size, _NORMAL_BLOCK, file, line); } inline void * __cdecl operator new [](size_t size, const char * file, int line) { return operator new (size, file, line); } inline void __cdecl operator delete( void * ptr) { MemoryAllocateTracker::GetInstance().re_free_dbg(ptr, _NORMAL_BLOCK); } inline void __cdecl operator delete[]( void * ptr) { delete ptr; } #ifdef DEBUG_NEW #undef DEBUG_NEW #endif #define DEBUG_NEW new (__FILE__, __LINE__) #define new DEBUG_NEW #ifdef malloc #undef malloc #endif #define malloc(s) MemoryAllocateTracker::GetInstance().re_malloc_dbg(s, _NORMAL_BLOCK, __FILE__, __LINE__) #ifdef calloc #undef calloc #endif #define calloc(c, s) MemoryAllocateTracker::GetInstance().re_calloc_dbg(c, s, _NORMAL_BLOCK, __FILE__, __LINE__) #ifdef realloc #undef realloc #endif #define realloc(p, s) MemoryAllocateTracker::GetInstance().re_realloc_dbg(p, s, _NORMAL_BLOCK, __FILE__, __LINE__) // #define _recalloc(p, c, s) _recalloc_dbg(p, c, s, _NORMAL_BLOCK, __FILE__, __LINE__) // #define _expand(p, s) _expand_dbg(p, s, _NORMAL_BLOCK, __FILE__, __LINE__) #ifdef free #undef free #endif #define free(p) MemoryAllocateTracker::GetInstance().re_free_dbg(p, _NORMAL_BLOCK) // #define _msize(p) _msize_dbg(p, _NORMAL_BLOCK) // #define _aligned_msize(p, a, o) _aligned_msize_dbg(p, a, o) // #define _aligned_malloc(s, a) _aligned_malloc_dbg(s, a, __FILE__, __LINE__) // #define _aligned_realloc(p, s, a) _aligned_realloc_dbg(p, s, a, __FILE__, __LINE__) // #define _aligned_recalloc(p, c, s, a) _aligned_recalloc_dbg(p, c, s, a, __FILE__, __LINE__) // #define _aligned_offset_malloc(s, a, o) _aligned_offset_malloc_dbg(s, a, o, __FILE__, __LINE__) // #define _aligned_offset_realloc(p, s, a, o) _aligned_offset_realloc_dbg(p, s, a, o, __FILE__, __LINE__) // #define _aligned_offset_recalloc(p, c, s, a, o) _aligned_offset_recalloc_dbg(p, c, s, a, o, __FILE__, __LINE__) // #define _aligned_free(p) _aligned_free_dbg(p) // // #define _malloca(s) _malloca_dbg(s, _NORMAL_BLOCK, __FILE__, __LINE__) // #define _freea(p) _freea_dbg(p, _NORMAL_BLOCK) // // #define _strdup(s) _strdup_dbg(s, _NORMAL_BLOCK, __FILE__, __LINE__) // #define _wcsdup(s) _wcsdup_dbg(s, _NORMAL_BLOCK, __FILE__, __LINE__) // #define _mbsdup(s) _strdup_dbg(s, _NORMAL_BLOCK, __FILE__, __LINE__) // #define _tempnam(s1, s2) _tempnam_dbg(s1, s2, _NORMAL_BLOCK, __FILE__, __LINE__) // #define _wtempnam(s1, s2) _wtempnam_dbg(s1, s2, _NORMAL_BLOCK, __FILE__, __LINE__) // #define _fullpath(s1, s2, le) _fullpath_dbg(s1, s2, le, _NORMAL_BLOCK, __FILE__, __LINE__) // #define _wfullpath(s1, s2, le) _wfullpath_dbg(s1, s2, le, _NORMAL_BLOCK, __FILE__, __LINE__) // #define _getcwd(s, le) _getcwd_dbg(s, le, _NORMAL_BLOCK, __FILE__, __LINE__) // #define _wgetcwd(s, le) _wgetcwd_dbg(s, le, _NORMAL_BLOCK, __FILE__, __LINE__) // #define _getdcwd(d, s, le) _getdcwd_dbg(d, s, le, _NORMAL_BLOCK, __FILE__, __LINE__) // #define _wgetdcwd(d, s, le) _wgetdcwd_dbg(d, s, le, _NORMAL_BLOCK, __FILE__, __LINE__) // #define _getdcwd_nolock(d, s, le) _getdcwd_lk_dbg(d, s, le, _NORMAL_BLOCK, __FILE__, __LINE__) // #define _wgetdcwd_nolock(d, s, le) _wgetdcwd_lk_dbg(d, s, le, _NORMAL_BLOCK, __FILE__, __LINE__) // #define _dupenv_s(ps1, size, s2) _dupenv_s_dbg(ps1, size, s2, _NORMAL_BLOCK, __FILE__, __LINE__) // #define _wdupenv_s(ps1, size, s2) _wdupenv_s_dbg(ps1, size, s2, _NORMAL_BLOCK, __FILE__, __LINE__) #if !__STDC__ #ifdef strdup #undef strdup #endif #define strdup(s) MemoryAllocateTracker::GetInstance().re_strdup_dbg(s, _NORMAL_BLOCK, __FILE__, __LINE__) #ifdef wcsdup #undef wcsdup #endif #define wcsdup(s) MemoryAllocateTracker::GetInstance().re_wcsdup_dbg(s, _NORMAL_BLOCK, __FILE__, __LINE__) #ifdef tempnam #undef tempnam #endif #define tempnam(s1, s2) MemoryAllocateTracker::GetInstance().re_tempnam_dbg(s1, s2, _NORMAL_BLOCK, __FILE__, __LINE__) // #ifdef getcwd // #undef getcwd // #endif // #define getcwd(s, le) MemoryAllocateTracker::GetInstance().re_getcwd_dbg(s, le, _NORMAL_BLOCK, __FILE__, __LINE__) #endif #endif
复制代码

MemoryAllocateTracker.h

复制代码
   
   
#pragma once #ifdef MEMORY_ALLOC_TRACKER #define MEMORY_ALLOC_TRACKER_CLASS _declspec(dllexport) #define MEMORY_ALLOC_TRACKER_FUNC _declspec(dllexport) #else #define MEMORY_ALLOC_TRACKER_CLASS _declspec(dllimport) #define MEMORY_ALLOC_TRACKER_FUNC _declspec(dllimport) #endif class MEMORY_ALLOC_TRACKER_CLASS MemoryAllocateTracker { public : enum AllocState { AS_NOW, AS_MIN, AS_MAX }; public : static MemoryAllocateTracker & GetInstance(); int GetAllocatedSize(AllocState state) const ; void Alloc( void * addr, size_t size, const char * file, long line); void Dealloc( void * addr); void WriteLog( const char * file = " C:\\temp\\MemoryLeakTracker.txt " ); public : void re_free_dbg( void * addr, int blockType); void * re_malloc_dbg(size_t size, int blockType, const char * file, int line); void * re_calloc_dbg(size_t num, size_t size, int blockType, const char * file, int line); void * re_realloc_dbg( void * addr, size_t size, int blockType, const char * file, int line); char * re_strdup_dbg( const char * str, int blockType, const char * file, int line ); wchar_t * re_wcsdup_dbg( const wchar_t * str, int blockType, const char * file, int line ); char * re_tempnam_dbg( const char * dirname, const char * filePrefix, int blockType, const char * file, int line ); char * re_getcwd_dbg( char * buf, int size, int blockType, const char * file, int line ); private : MemoryAllocateTracker(); ~ MemoryAllocateTracker(); };
复制代码

MemoryAllocateTracker.pp

复制代码
   
   
#include < string > #include < iomanip > #include < fstream > #include < map > #include < set > #include " MemoryAllocateTracker.h " #ifndef _CRTBLD #define _CRTBLD #include < dbgint.h > #endif #pragma data_seg("SharedData") namespace { long g_TotalAllocCount = 0 ; HANDLE g_hProcHeap = 0 ; // TEMPLATE CLASS allocator template < class _Ty > class SpecAllocator { // generic allocator for objects of class _Ty public : typedef typename _Ty value_type; typedef value_type _FARQ * pointer; typedef value_type _FARQ & reference; typedef const value_type _FARQ * const_pointer; typedef const value_type _FARQ & const_reference; typedef _SIZT size_type; typedef _PDFT difference_type; template < class _Other > struct rebind { // convert an allocator<_Ty> to an allocator <_Other> typedef SpecAllocator < _Other > other; }; pointer address(reference _Val) const { // return address of mutable _Val return ( & _Val); } const_pointer address(const_reference _Val) const { // return address of nonmutable _Val return ( & _Val); } SpecAllocator() _THROW0() { // construct default allocator (do nothing) } SpecAllocator( const SpecAllocator < _Ty >& ) _THROW0() { // construct by copying (do nothing) } template < class _Other > SpecAllocator( const SpecAllocator < _Other >& ) _THROW0() { // construct from a related allocator (do nothing) } template < class _Other > SpecAllocator < _Ty >& operator = ( const SpecAllocator < _Other >& ) { // assign from a related allocator (do nothing) return ( * this ); } void deallocate(pointer _Ptr, size_type) { // deallocate object at _Ptr, ignore size // ::HeapFree(g_hProcHeap, 0, _Ptr); free(_Ptr); } pointer allocate(size_type _Count) { // allocate array of _Count elements g_TotalAllocCount += _Count; // check for integer overflow if (_Count <= 0 ) _Count = 0 ; else if (((_SIZT)( - 1 ) / _Count) < sizeof (_Ty)) _THROW_NCEE(std::bad_alloc, NULL); // return (pointer)::HeapAlloc(g_hProcHeap, 0, _Count); return (pointer)_malloc_dbg(_Count * sizeof (_Ty), 1 , __FILE__, __LINE__); } pointer allocate(size_type _Count, const void _FARQ * ) { // allocate array of _Count elements, ignore hint return (allocate(_Count)); } void construct(pointer _Ptr, const _Ty & _Val) { // construct object at _Ptr with value _Val _Construct(_Ptr, _Val); } void destroy(pointer _Ptr) { // destroy object at _Ptr _Destroy(_Ptr); } _SIZT max_size() const _THROW0() { // estimate maximum array size _SIZT _Count = (_SIZT)( - 1 ) / sizeof (_Ty); return ( 0 < _Count ? _Count : 1 ); } }; // typedef std::basic_string<char, std::char_traits<char>, SpecAllocator<char> > SpecString; typedef char * SpecString; // typedef std::string SpecString; typedef std:: set < int , std::less < int > , SpecAllocator < int > > SpecSet; struct TrackerNode { SpecString file; long lineNum; long allocSize; long count; long totalCount; long leakCount; TrackerNode( const char * f = 0 , long l = 0 , long s = 0 , long c = 1 ) : file(f != 0 ? f : " (No file path!) " ), lineNum(l),allocSize(s), count(c), totalCount( 1 ), leakCount( 0 ) { } TrackerNode( const TrackerNode & o) : file(o.file), lineNum(o.lineNum),allocSize(o.allocSize), count(o.count), totalCount( 1 ), leakCount( 0 ) { } ~ TrackerNode() { } static void * operator new (size_t size) { return _malloc_dbg(size, 1 , __FILE__, __LINE__); // return ::HeapAlloc(g_hProcHeap, 0, size); } static void operator delete( void * ptr) { // ::HeapFree(g_hProcHeap, 0, ptr); free(ptr); } }; // todo: It should be changed it to shared ptr later. typedef TrackerNode * TrackerNodePtr; typedef const TrackerNode * TrackerNodeConstPtr; inline bool operator < ( const TrackerNode & lt, const TrackerNode & rh) { if (lt.lineNum < rh.lineNum) { return true ; } else if (lt.lineNum == rh.lineNum && lt.file < rh.file) { return true ; } else if (lt.lineNum == rh.lineNum && lt.file == rh.file && lt.allocSize < rh.allocSize) { return true ; } return false ; } template < class _Ty = TrackerNode > struct LessForSort: public std::binary_function < _Ty, _Ty, bool > { bool operator () ( const _Ty & lt, const _Ty & rh) const { return lt.allocSize * lt.count > rh.allocSize * rh.count; } }; } template <> struct std::less < TrackerNodePtr > : public std::binary_function < TrackerNodePtr, TrackerNodePtr, bool > { bool operator () ( const TrackerNodePtr & lt, const TrackerNodePtr & rh) const { if (lt -> lineNum < rh -> lineNum) { return true ; } else if (lt -> lineNum == rh -> lineNum && lt -> file < rh -> file) { return true ; } else if (lt -> lineNum == rh -> lineNum && lt -> file == rh -> file && lt -> allocSize < rh -> allocSize) { return true ; } return false ; } }; namespace { struct AddrCountPair { long count; TrackerNodePtr addr; AddrCountPair( long c = 0 , TrackerNodePtr ptr = 0 ): count(c), addr(ptr) {} }; typedef std::map < int * ,AddrCountPair ,std::less < int *> ,SpecAllocator < std::pair < const int * , AddrCountPair > > > TrackerPtrMap; typedef TrackerPtrMap::iterator TrackerPtrMapItr; typedef std:: set < TrackerNodePtr ,std::less < TrackerNodePtr > ,SpecAllocator < TrackerNodePtr > > TrackerPtrSet; typedef TrackerPtrSet::iterator TrackerPtrSetItr; typedef std:: set < TrackerNode ,std::less < TrackerNode > ,SpecAllocator < TrackerNode > > TrackerSet; typedef TrackerSet::iterator TrackerSetItr; typedef std:: set < TrackerNode ,LessForSort <> ,SpecAllocator < TrackerNode > > TrackerSortedSet; typedef TrackerSortedSet::iterator TrackerSortedSetItr; long g_totalAlloc = 0 ; TrackerPtrMap g_allocMap; TrackerPtrSet g_allocSet; CMemoryState g_mfcMemStateBegin, g_mfcMemStateEnd; } namespace { class Mutex { friend class Lock; public : Mutex () { InitializeCriticalSection ( & _critSection); } ~ Mutex () { DeleteCriticalSection ( & _critSection); } private : void Acquire () { EnterCriticalSection ( & _critSection); } void Release () { LeaveCriticalSection ( & _critSection); } private : CRITICAL_SECTION _critSection; }; Mutex _mutex; class Lock { public : // Acquire the state of the semaphore Lock () { _mutex.Acquire(); } // Release the state of the semaphore ~ Lock () { _mutex.Release(); } }; } // see bellow...
复制代码
复制代码
   
   
MemoryAllocateTracker::MemoryAllocateTracker() { if (g_hProcHeap == 0 ) { // g_hProcHeap = ::HeapCreate(HEAP_CREATE_ENABLE_EXECUTE, 0, 0); } g_mfcMemStateBegin.Checkpoint(); } MemoryAllocateTracker:: ~ MemoryAllocateTracker() { Lock threadlock; WriteLog(); if (g_hProcHeap != 0 ) { // ::HeapDestroy(g_hProcHeap); g_hProcHeap = 0 ; } } int MemoryAllocateTracker::GetAllocatedSize(AllocState state) const { return 0 ; } void MemoryAllocateTracker::Alloc( void * addr, size_t size, const char * file, long line) { Lock threadlock; g_totalAlloc += size; TrackerNode node(file, line, size, 1 ) ; TrackerPtrSetItr it = g_allocSet.find( & node); if (it != g_allocSet.end()) { ( * it) -> count ++ ; ( * it) -> totalCount ++ ; g_allocMap[( int * )addr] = AddrCountPair(( * it) -> totalCount, ( * it)); } else { TrackerNodePtr nodeptr = new TrackerNode(node); g_allocSet.insert(nodeptr); g_allocMap[( int * )addr] = AddrCountPair(nodeptr -> totalCount, nodeptr); } } void MemoryAllocateTracker::Dealloc( void * addr) { Lock threadlock; TrackerPtrMapItr it = g_allocMap.find(( int * )addr); if (it != g_allocMap.end()) { g_totalAlloc -= it -> second.addr -> allocSize; -- (it -> second.addr -> count); g_allocMap.erase(it); g_TotalAllocCount -- ; } } MemoryAllocateTracker & MemoryAllocateTracker::GetInstance() { static MemoryAllocateTracker tracker; return tracker; } void MemoryAllocateTracker::WriteLog( const char * file) { double totalSizeAllocatedBySelf = double (g_TotalAllocCount) / 1024 ; if ( true ) { std::ofstream out ( " C:\\temp\\_MemoryLeakTracker.txt " ); if ( out .fail()) { return ; } out << std::setw( 24 ) << std::setprecision( 3 ) << " \t Total Size Allocated by MemoryAllocateTracker.dll:\t " << totalSizeAllocatedBySelf << " kb \n " << std::endl << " \t Total Size of Memory Leak(without MFC):\t " << double (g_totalAlloc) / 1024 << " kb \n " << std::endl << " \t Size(bytes) \t Count(times) \t Total(kb) \t First Leak Count \t Line number \t file location\n\n " ; for (TrackerPtrMapItr it = g_allocMap.begin(); it != g_allocMap.end(); ++ it) { AddrCountPair & pair = it -> second; if (pair.addr -> leakCount <= 0 || pair.count < pair.addr -> leakCount) { pair.addr -> leakCount = pair.count; } } for (TrackerPtrSetItr it = g_allocSet.begin(); it != g_allocSet.end();) { TrackerNodePtr ptr = * it; if (ptr -> count > 0 ) { out << " \t " << ptr -> allocSize << " \t\t " << ptr -> count << " \t\t " << double (ptr -> count * ptr -> allocSize) / 1024 << " \t\t " << ptr -> leakCount << " \t\t " << ptr -> lineNum << " \t\t " << ptr -> file << std::endl; } it = g_allocSet.erase(it); // Do not use free(ptr), else memory of (*ptr)->file is not released. delete ptr; } g_allocMap.clear(); out .flush(); out .close(); } g_mfcMemStateEnd.Checkpoint(); TrackerSet trackerSet ; _CrtMemBlockHeader * ptr = g_mfcMemStateEnd.m_memState.pBlockHeader; long mfcLeakSize = 0 ; while (ptr && ptr != g_mfcMemStateBegin.m_memState.pBlockHeader) { TrackerNode node(ptr -> szFileName, ptr -> nLine, ptr -> nDataSize, 1 ); mfcLeakSize += ptr -> nDataSize; TrackerSetItr it = trackerSet.find(node); if (it != trackerSet.end()) { it -> count ++ ; } else { trackerSet.insert(node); } ptr = ptr -> pBlockHeaderNext; } std::ofstream mfcOut(file); mfcOut << std::setw( 16 ) << std::setprecision( 3 ); mfcOut << " \t Total Size Allocated by MemoryAllocateTracker.dll:\t " << totalSizeAllocatedBySelf << " kb \n " << std::endl << " \n\t Total Size of Memory Leak:\t " << double (mfcLeakSize) / 1024 << " kb\n " << std::endl << " \t Size(bytes) \t Count(times) \t Total(kb) \t Line number \t file location " << std::endl; const bool needChecked = false ; if (needChecked && ptr) { _CrtMemBlockHeader * xptr = ptr; _CrtMemBlockHeader * rexptr = g_mfcMemStateBegin.m_memState.pBlockHeader; size_t count = 0 ; while (xptr || rexptr) { if (xptr != rexptr || ++ count > 1000 ) { mfcOut << " Got Stupid ! " << std::endl; break ; } xptr = xptr ? xptr -> pBlockHeaderNext : xptr; rexptr = rexptr ? rexptr -> pBlockHeaderNext : rexptr; } } TrackerSortedSet sortedSet(trackerSet.begin(), trackerSet.end()); for (TrackerSortedSetItr it = sortedSet.begin(); it != sortedSet.end(); ++ it) { mfcOut << " \t " << it -> allocSize << " \t\t " << it -> count << " \t\t " << double (it -> allocSize * it -> count) / 1024 << " \t\t " << it -> lineNum << " \t\t " << it -> file << std::endl; } mfcOut << " \n\n\t========================================== " << " File Order ==========================================\n\n " ; for (TrackerSetItr it = trackerSet.begin(); it != trackerSet.end(); ++ it) { mfcOut << " \t " << it -> allocSize << " \t\t " << it -> count << " \t\t " << double (it -> allocSize * it -> count) / 1024 << " \t\t " << it -> lineNum << " \t\t " << it -> file << std::endl; } mfcOut.flush(); mfcOut.close(); } void MemoryAllocateTracker::re_free_dbg( void * addr, int blockType) { _free_dbg(addr, blockType); Dealloc(addr); } void * MemoryAllocateTracker::re_malloc_dbg(size_t size, int blockType, const char * file, int line) { void * addr = _malloc_dbg(size, blockType, file, line); Alloc(addr, size, file, line); return addr; } void * MemoryAllocateTracker::re_calloc_dbg(size_t num, size_t size, int blockType, const char * file, int line) { void * addr = _calloc_dbg(num, size, blockType, file, line); Alloc(addr, num * size, file, line); return addr; } void * MemoryAllocateTracker::re_realloc_dbg( void * addr, size_t size, int blockType, const char * file, int line) { addr = _realloc_dbg(addr, size, blockType, file, line); Alloc(addr, size, file, line); return addr; } char * MemoryAllocateTracker::re_strdup_dbg( const char * str, int blockType, const char * file, int line ) { char * addr = _strdup_dbg(str, blockType, file, line); Alloc(addr, strlen(addr), file, line); return addr; } wchar_t * MemoryAllocateTracker::re_wcsdup_dbg( const wchar_t * str, int blockType, const char * file, int line ) { wchar_t * addr = _wcsdup_dbg(str, blockType, file, line); Alloc(addr, wcslen(addr), file, line); return addr; } char * MemoryAllocateTracker::re_tempnam_dbg( const char * dirname, const char * filePrefix, int blockType, const char * file, int line ) { char * addr = _tempnam_dbg(dirname, filePrefix, blockType, file, line); Alloc(addr, 123 , file, line); return addr; } char * MemoryAllocateTracker::re_getcwd_dbg( char * buf, int size, int blockType, const char * file, int line ) { char * addr = _getcwd_dbg(buf, size, blockType, file, line); Alloc(addr, 123 , file, line); return addr; }
 
#pragma data_seg()
#pragma comment(linker,"/section:SharedData,rws")
复制代码
  

For MFC memory check, please refer to Detecting memory leaks: by using CRT diagnostic functions - Part1

and Inside CRT: Debug Heap Management

To figure out the function call stack, you need to use dbhelp API within the source above under windows NT.

Or else, Visual Leak Detector is also a good choice, also see http://vld.codeplex.com/.


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值