Memory leak detector(C++)

本文介绍了一种简单的C++内存泄漏检测方案,适用于Windows平台。通过覆盖new、delete等操作符并记录分配信息来追踪内存分配和释放情况,帮助开发者定位内存泄漏问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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/.

转载于:https://www.cnblogs.com/sunkang/archive/2011/05/20/2052020.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值