windows mobile下記憶體檢測,一些工具如AppVertifyer等其實檢測效果並不佳,而更多的是需要程式員在編寫代碼過程中注意加入檢測代碼, 以下這個類可以當做檢測windows mobile下記憶體,主要是對new 、delete進行重寫,然後在需要檢測的檔案中添加宏定義。
crtdbg.h標頭檔代碼如下:
/*****************************************************************</p><p>FILENAME:crtdbg.h</p><p>AUTHOR:Ciprian Miclaus (Ciprian_Miclaus@yahoo.com)</p><p>DESCRIPTION:<br />Detects memory leaks in eVC++ almost the same way crtdbg does in VC++.<br />At the end of program execution it will display in the debug window if<br />there were any memory leaks and how the memory looks so you can identify<br />where your memory leak occurred. It will display in the debug window a<br />message saying no memory leaks detected if there are no memory leaks.<br />Similar to what crtdbg does in VC++.<br />It will fail to display the line same as crtdbg does.<br />There are 3 simple steps in order to enable memory leak detection:<br />1. Define _DEBUG<br />#define _DEBUG<br />2. Include "crtdbg.h"<br />#include "crtdbg.h"<br />3. Let your first line in the code be:<br />_CrtSetDbgFlag (ON);</p><p>Tips on debugging:<br />Tip 1:<br />Altho it doesn't display the line where the memory leak occurred (read<br />Tip 2), the utility display the address in hexa, and you can add a small<br />code to the operator new function, just after the first malloc:<br />if (retPtr == (void*)0x76DA0)<br />dumb instruction; <- place a breakpoint on this one<br />so you can detect easily which line of your code called the operator new<br />to allocate memory at the specified address and wasn't freed.<br />Tip 2:<br />Here's a trick that allow you to get the correct line and filename where<br />the memory leak occurred. Define the following line in every file, or define<br />it in a .h and include it in every file where you want accurate line and<br />filename:</p><p>#define new new(_T(__FILE__), __LINE__)</p><p>Happy debugging!</p><p>LICENSE: Public domain</p><p>COMMENTS:<br />Please report any bugs to Ciprian_Miclaus@yahoo.com.<br />You can use and distribute this code freely, but please keep these<br />few lines.<br />If you make any improvements, or have any ideas about how this code<br />could be improved or just you feel you need to comment this code in<br />any way, please send your comments, idea, imporvements to me to my<br />email above.<br />The code doesn't detect memory leaks generated with C functions:<br />malloc, calloc, free, but that can be done in the future. Let me know<br />and I will program it.</p><p>********************************************************************/</p><p>#ifndef _CRTDBG_HEADER<br />#define _CRTDBG_HEADER</p><p>#ifdef _DEBUG</p><p>#include <stdlib.h><br />#include <malloc.h><br />#include <string.h><br />#include <tchar.h></p><p>#include <dbgapi.h></p><p>//un-comment this line if you get an error:<br />//Unresolved ... NKDbgPrintfW...<br />//extern "C" void WINAPIV NKDbgPrintfW(LPWSTR lpszFmt, ...);</p><p>struct _CrtFileName {<br />unsigned short*_CrtName;<br />_CrtFileName*_CrtNext;<br />};</p><p>struct _CrtMem {<br />_CrtFileName*_CrtFileName;<br />int_CrtLine;<br />unsigned int_CrtMemLen;<br />void*_CrtMemAddr;<br />_CrtMem*_CrtNext;<br />};</p><p>void* operator new(<br /> unsigned int s,<br /> unsigned short* name,<br /> int line<br /> );</p><p>inline void* __cdecl operator new(unsigned int s)<br />{ return ::operator new(s, _T(__FILE__), __LINE__); }</p><p>void __cdecl operator delete(void *pvMem);</p><p>class garbageCollector {<br />public:<br />garbageCollector () {}<br />~garbageCollector ();<br />};</p><p>#define _CrtSetDbgFlag(ignore) /<br />garbageCollectorgb;</p><p>void* operator new(unsigned int s,unsigned short* name,int line);</p><p>void __cdecl operator delete(void *pvMem);</p><p>#else</p><p>#define _CrtSetDbgFlag(ignore)</p><p>#endif //DEBUG</p><p>#endif //HEADER
crtdbg.cpp代碼如下:
#include "stdafx.h"<br />#include "crtdbg.h"</p><p>_CrtMem*_CrtMemRoot = 0;<br />_CrtFileName*_CrtFileNameRoot = 0;<br />unsigned longmaxMem = 0;<br />unsigned longcurrMem = 0;</p><p>void* operator new(<br /> unsigned int s,<br /> unsigned short* name,<br /> int line<br /> )<br />{<br />void*retPtr = malloc (s);<br />if (retPtr) {<br />currMem += s;<br />if (currMem > maxMem)<br />{<br />maxMem = currMem;<br />}<br />_CrtMem*_crtMemCell = (struct _CrtMem*)malloc (sizeof(_CrtMem));<br />_crtMemCell->_CrtLine= line;<br />_crtMemCell->_CrtMemLen= s;<br />_crtMemCell->_CrtMemAddr= retPtr;<br />_crtMemCell->_CrtNext= 0;</p><p>_CrtFileName*_tmpCrtFileName;<br />for (_tmpCrtFileName = _CrtFileNameRoot; _tmpCrtFileName && wcscmp(name, _tmpCrtFileName->_CrtName); _tmpCrtFileName = _tmpCrtFileName->_CrtNext);<br />if (!_tmpCrtFileName) {<br />unsigned short*_crtName = (unsigned short*)malloc ((wcslen (name) + 1) * sizeof(unsigned short));<br />wcscpy (_crtName, name);<br />_CrtFileName*_crtFileName = (struct _CrtFileName*)malloc (sizeof (_CrtFileName));<br />_crtFileName->_CrtName = _crtName;<br />_crtFileName->_CrtNext = 0;<br />if (!_CrtFileNameRoot)<br />_CrtFileNameRoot = _crtFileName;<br />else {<br />for (_tmpCrtFileName = _CrtFileNameRoot; _tmpCrtFileName->_CrtNext; _tmpCrtFileName = _tmpCrtFileName->_CrtNext);<br />_tmpCrtFileName->_CrtNext = _crtFileName;<br />}<br />_tmpCrtFileName = _crtFileName;<br />}<br />_crtMemCell->_CrtFileName = _tmpCrtFileName;</p><p>if (!_CrtMemRoot) {<br />_CrtMemRoot= _crtMemCell;<br />}<br />else {<br />_CrtMem*_tmpMemPtr;<br />for (_tmpMemPtr = _CrtMemRoot; _tmpMemPtr->_CrtNext; _tmpMemPtr = _tmpMemPtr->_CrtNext);<br />_tmpMemPtr->_CrtNext = _crtMemCell;<br />}<br />}</p><p>return retPtr;</p><p>}</p><p>void __cdecl operator delete(void *pvMem)<br />{<br />if (pvMem) {<br />_CrtMem*_tmpMem;<br />if (pvMem == _CrtMemRoot->_CrtMemAddr) {<br />_tmpMem= _CrtMemRoot;<br />_CrtMemRoot= _CrtMemRoot->_CrtNext;<br />currMem -= _tmpMem->_CrtMemLen;<br />free (_tmpMem);<br />}<br />else {<br />for (_tmpMem = _CrtMemRoot; _tmpMem->_CrtNext && (_tmpMem->_CrtNext->_CrtMemAddr != pvMem); _tmpMem = _tmpMem->_CrtNext);<br />if (_tmpMem->_CrtNext) {<br />_CrtMem*_tmpMem2;<br />_tmpMem2= _tmpMem->_CrtNext;<br />_tmpMem->_CrtNext = _tmpMem2->_CrtNext;<br />currMem -= _tmpMem2->_CrtMemLen;<br />free (_tmpMem2);<br />}<br />else<br />NKDbgPrintfW (_T("%s(%i) : Warning : deletes memory pointer not allocated with new!/n"), _T(__FILE__), __LINE__);<br />}<br />free (pvMem);<br />}<br />}</p><p>garbageCollector::~garbageCollector ()<br />{<br />if (!_CrtMemRoot)<br />NKDbgPrintfW (_T("No memory leaks detected!/n"));<br />else {<br />_CrtMem*_tmpMem;<br />NKDbgPrintfW (_T("Detected memory leaks!/nDumping objects ->/n"));<br />for (_tmpMem = _CrtMemRoot; _tmpMem; _tmpMem = _tmpMem->_CrtNext) {<br />NKDbgPrintfW (_T("%s(%i) : normal block at 0x%08X, %i bytes long/n Data <"), _tmpMem->_CrtFileName->_CrtName, _tmpMem->_CrtLine, _tmpMem->_CrtMemAddr, _tmpMem->_CrtMemLen);<br />unsigned int _length = _tmpMem->_CrtMemLen < 100 ? _tmpMem->_CrtMemLen : 50;<br />for (unsigned int i = 0; i < _length; i++)<br />NKDbgPrintfW (_T("%c"), *(((char*)_tmpMem->_CrtMemAddr)+i));<br />NKDbgPrintfW (_T(">/n"));<br />}<br />}<br />_CrtFileName*_tmpName = _CrtFileNameRoot;<br />for (;_tmpName;) {<br />_CrtFileNameRoot= _tmpName->_CrtNext;<br />free(_tmpName->_CrtName);<br />free(_tmpName);<br />_tmpName= _CrtFileNameRoot;<br />}</p><p>NKDbgPrintfW (_T("Maximum free store memory allocated at a time: %lu!/n"), maxMem);</p><p>}
然後在程式的main函數裡添加_CrtSetDbgFlag (ON); 其實這是一個#define _CrtSetDbgFlag(ignore) /
garbageCollector gb; 這樣的定義 , 在程式退出的時候會調用garbageCollector 的解構函式,crtdbg.cpp中有定義全域變數負責管理我們程式中分配的記憶體,這樣子當garbageCollector 析構的時候會調用這些全域變數來判斷new的記憶體是否有delete掉。
不紡做個測試:
#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;
return 0;
}
程式輸出:
Detected memory leaks!
Dumping objects ->
d:/eclipse3.4.3/ce_leakdemo/crtdbg.h(95) : normal block at 0x00030060, 4 bytes long
Data <>
./test.cpp(24) : normal block at 0x00030100, 4 bytes long
Data <>
Maximum free store memory allocated at a time: 8!
我在windows mobile上調試這個類是要在項目屬性的c/c++ ---》語言-->將wchar_t設定為內建類型設定為否編譯才通過
一般來說
#include "crtdbg.h"
#define new new(_T(__FILE__), __LINE__) 這兩行要加在所有include標頭檔的最後面,這樣不會影響到你所包含的標頭檔裡的new、delete的調用,但如果你樂意也可以,呵呵。