Windows mobile下检测内存泄露的方法

本文介绍了一种在Windows Mobile环境下通过代码实现内存泄漏检测的方法。该方法通过重载new操作符并在分配内存时记录文件名和行号,利用自定义的垃圾收集器类在程序结束时检查未释放的内存块,帮助开发者定位内存泄漏发生的位置。

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

 Windows mobile下由于内存小,所以内存泄露成为一个严重的问题。使用工具检测的效果往往没有预期的那么好,下列提供一种在代码中增加内存泄露检测的方法:

 

由于内存泄露一般都是由于堆空间内存泄露引起的,所以在c++中我们可以对new方法进行重载,如下:

 

#ifndef _DEBUG
#define _DEBUG
#endif

#include "crtdbg.h"

#define new new(_T(__FILE__), __LINE__)

int WINAPI WinMain( HINSTANCE hInstance,
     HINSTANCE hPrevInstance,
     LPTSTR    lpCmdLine,
     int       nCmdShow)
{
  // TODO: Place code here.
 _CrtSetDbgFlag (ON);
 int* p = new int;
 *p = 10;


 return 0;
}

 _CrtSetDbgFlag (ON); 这个其实只是定义了一个类:

 

#define _CrtSetDbgFlag(ignore) /
  garbageCollector gb;

 

在这个类里标记了一个_CrtMemRoot,在new的时候我们将内存地址标记在这个标记当中,当析构这个类的时候我们再去判断这个标记是否存在,如果没有调用delete的话,这个标记就不为空,因此就发现出内存泄露。

crtdbg.h文件内容如下:

 

/*****************************************************************

FILENAME: crtdbg.h

AUTHOR:  Ciprian Miclaus (Ciprian_Miclaus@yahoo.com)

DESCRIPTION:
Detects memory leaks in eVC++ almost the same way crtdbg does in VC++.
At the end of program execution it will display in the debug window if
there were any memory leaks and how the memory looks so you can identify
where your memory leak occurred. It will display in the debug window a
message saying no memory leaks detected if there are no memory leaks.
Similar to what crtdbg does in VC++.
It will fail to display the line same as crtdbg does.
There are 3 simple steps in order to enable memory leak detection:
1. Define _DEBUG
#define _DEBUG
2. Include "crtdbg.h"
#include "crtdbg.h"
3. Let your first line in the code be:
_CrtSetDbgFlag (ON);

Tips on debugging:
Tip 1:
Altho it doesn't display the line where the memory leak occurred (read
Tip 2), the utility display the address in hexa, and you can add a small
code to the operator new function, just after the first malloc:
 if (retPtr == (void*)0x76DA0)
  dumb instruction; <- place a breakpoint on this one
so you can detect easily which line of your code called the operator new
to allocate memory at the specified address and wasn't freed.
Tip 2:
Here's a trick that allow you to get the correct line and filename where
the memory leak occurred. Define the following line in every file, or define
it in a .h and include it in every file where you want accurate line and
filename:

#define new new(_T(__FILE__), __LINE__)

Happy debugging!

LICENSE: Public domain

COMMENTS:
Please report any bugs to Ciprian_Miclaus@yahoo.com.
You can use and distribute this code freely, but please keep these
few lines.
If you make any improvements, or have any ideas about how this code
could be improved or just you feel you need to comment this code in
any way, please send your comments, idea, imporvements to me to my
email above.
The code doesn't detect memory leaks generated with C functions:
malloc, calloc, free, but that can be done in the future. Let me know
and I will program it.

********************************************************************/

#ifndef _CRTDBG_HEADER
#define _CRTDBG_HEADER

#ifdef _DEBUG

#include <stdlib.h>
#include <malloc.h>
#include <string.h>
#include <tchar.h>

#include <dbgapi.h>

//un-comment this line if you get an error:
//Unresolved ... NKDbgPrintfW...
//extern "C" void WINAPIV NKDbgPrintfW(LPWSTR lpszFmt, ...);


struct _CrtFileName {
 unsigned short* _CrtName;
 _CrtFileName* _CrtNext;
};

struct _CrtMem {
 _CrtFileName* _CrtFileName;
 int    _CrtLine;
 unsigned int _CrtMemLen;
 void*   _CrtMemAddr;
 _CrtMem*  _CrtNext;
};

void* operator new(
        unsigned int s,
        unsigned short* name,
        int line
        );

inline void* __cdecl operator new(unsigned int s)
        { return ::operator new(s, (unsigned short *)__FILE__, __LINE__); }

void __cdecl operator delete(void *pvMem);

class garbageCollector {
public:
 garbageCollector () {}
 ~garbageCollector ();
};

#define _CrtSetDbgFlag(ignore) /
  garbageCollector gb;

 

_CrtMem*   _CrtMemRoot = 0;
_CrtFileName*  _CrtFileNameRoot = 0;
unsigned long  maxMem = 0;
unsigned long  currMem = 0;


void* operator new(
        unsigned int s,
        unsigned short* name,
        int line
        )
{
 void* retPtr = malloc (s);
 if (retPtr)
 {
  currMem += s;
  if (currMem > maxMem)
  {
   maxMem = currMem;
  }
  _CrtMem* _crtMemCell = (struct _CrtMem*)malloc (sizeof(_CrtMem));
  _crtMemCell->_CrtLine  = line;
  _crtMemCell->_CrtMemLen  = s;
  _crtMemCell->_CrtMemAddr = retPtr;
  _crtMemCell->_CrtNext  = 0;
  
  _CrtFileName* _tmpCrtFileName;
  for (_tmpCrtFileName = _CrtFileNameRoot; _tmpCrtFileName && wcscmp((wchar_t *)name, (const wchar_t *)_tmpCrtFileName->_CrtName); _tmpCrtFileName = _tmpCrtFileName->_CrtNext);
  if (!_tmpCrtFileName)
  {
   unsigned short* _crtName = (unsigned short*)malloc ((wcslen ((wchar_t *)name) + 1) * sizeof(unsigned short));
   wcscpy ((wchar_t *)_crtName,(wchar_t *) name);
   _CrtFileName* _crtFileName = (struct _CrtFileName*)malloc (sizeof (_CrtFileName));
   _crtFileName->_CrtName = _crtName;
   _crtFileName->_CrtNext = 0;
   if (!_CrtFileNameRoot)
    _CrtFileNameRoot = _crtFileName;
   else
   {
    for (_tmpCrtFileName = _CrtFileNameRoot; _tmpCrtFileName->_CrtNext; _tmpCrtFileName = _tmpCrtFileName->_CrtNext);
    _tmpCrtFileName->_CrtNext = _crtFileName;
   }
   _tmpCrtFileName = _crtFileName;
  }
  _crtMemCell->_CrtFileName = _tmpCrtFileName;

  if (!_CrtMemRoot)
  {
   _CrtMemRoot  = _crtMemCell;
  }
  else
  {
   _CrtMem* _tmpMemPtr;
   for (_tmpMemPtr = _CrtMemRoot; _tmpMemPtr->_CrtNext; _tmpMemPtr = _tmpMemPtr->_CrtNext);
   _tmpMemPtr->_CrtNext = _crtMemCell;
  }
 }

 return retPtr;

}

void __cdecl operator delete(void *pvMem)
{
 if (pvMem)
 {
  _CrtMem* _tmpMem;
  if (pvMem == _CrtMemRoot->_CrtMemAddr)
  {
   _tmpMem   = _CrtMemRoot;
   _CrtMemRoot  = _CrtMemRoot->_CrtNext;
   currMem -= _tmpMem->_CrtMemLen;
   free (_tmpMem);
  }
  else
  {
   for (_tmpMem = _CrtMemRoot; _tmpMem->_CrtNext && (_tmpMem->_CrtNext->_CrtMemAddr != pvMem); _tmpMem = _tmpMem->_CrtNext);
   if (_tmpMem->_CrtNext)
   {
    _CrtMem* _tmpMem2;
    _tmpMem2 = _tmpMem->_CrtNext;
    _tmpMem->_CrtNext = _tmpMem2->_CrtNext;
    currMem -= _tmpMem2->_CrtMemLen;
    free (_tmpMem2);
   }
   else
    NKDbgPrintfW (_T("%s(%i) : Warning : deletes memory pointer not allocated with new!/n"), _T(__FILE__), __LINE__);
  }
  free (pvMem);
 }
}

garbageCollector::~garbageCollector ()
{
 if (!_CrtMemRoot)
  NKDbgPrintfW (_T("No memory leaks detected!/n"));
 else
 {
  _CrtMem* _tmpMem;
  NKDbgPrintfW (_T("Detected memory leaks!/nDumping objects ->/n"));
  for (_tmpMem = _CrtMemRoot; _tmpMem; _tmpMem = _tmpMem->_CrtNext) {
   NKDbgPrintfW (_T("%s(%i) : normal block at 0x%08X, %i bytes long/n Data <"), _tmpMem->_CrtFileName->_CrtName, _tmpMem->_CrtLine, _tmpMem->_CrtMemAddr, _tmpMem->_CrtMemLen);
   unsigned int _length = _tmpMem->_CrtMemLen < 100 ? _tmpMem->_CrtMemLen : 50;
   for (unsigned int i = 0; i < _length; i++)
    NKDbgPrintfW (_T("%c"), *(((char*)_tmpMem->_CrtMemAddr)+i));
   NKDbgPrintfW (_T(">/n"));
  }
 }
 _CrtFileName* _tmpName = _CrtFileNameRoot;
 for (;_tmpName;)
 {
  _CrtFileNameRoot = _tmpName->_CrtNext;
  free(_tmpName->_CrtName);
  free(_tmpName);
  _tmpName   = _CrtFileNameRoot;
 }

 NKDbgPrintfW (_T("Maximum free store memory allocated at a time: %lu!/n"), maxMem);

}

#else

#define _CrtSetDbgFlag(ignore)

#endif //DEBUG

#endif //HEADER

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值