記憶體洩漏檢測(自己寫的) 作者 很土
關鍵字 記憶體洩漏 記憶體 debug heap 堆
原作者姓名 很土
介紹簡單說明了一下沒有工具的情況如何運用vc庫中的工具來檢查**的記憶體洩漏問題
讀者評分 8 評分次數 2
正文記憶體洩漏檢測
一: 記憶體洩漏
記憶體洩漏是程式設計中常常見到的乙個問題. 記憶體洩漏往往會一種奇怪的方式來表現出來,基本上每個程式都表現出不同的方式. 但是一般最後的結果只有兩個,乙個是程式當掉.乙個是系統記憶體不足. 還有一種就是比較介於中間的結果程式不會當,但是系統的反映時間明顯降低,需要定時的reboot才會正常.
有乙個很簡單的辦法來檢查乙個程式是否有記憶體洩漏.就是是用windows的任務管理器(task manager). 執行程式,然後在任務管理器裡面檢視 「記憶體使用」和」虛擬記憶體大小」兩項,當程式請求了它所需要的記憶體之後,如果虛擬記憶體還是持續的增長的話,就說明了這個程式有記憶體洩漏問題. 當然如果記憶體洩漏的數目非常的小,用這種方法可能要過很長時間才能看的出來.
當然最簡單的辦法大概就是用compuware的boundchecker 之類的工具來檢測了,不過這些工具的**對於個人來講稍微有點奢侈了.
如果是已經發布的程式,檢查是否有記憶體洩漏是又費時又費力. 所以記憶體洩漏應該在code的生成過程就要時刻進行檢查.
二: 原因
而記憶體洩漏產生的原因一般是三種情況: 1.分配完記憶體之後忘了**.2. 程式code有問題,造成沒有辦法**.3.某些api函式操作不正確,造成記憶體洩漏.
1. 記憶體忘記**,這個是不應該的事情.但是也是在**種很常見的問題.分配記憶體之後,用完之後,就一定要**. 如果不**,那就造成了記憶體的洩漏,造成記憶體洩漏的code如果被經常呼叫的話,那記憶體洩漏的數目就會越來越多的.從而影響整個系統的執行. 比如下面的**
for (int =0;i<100;i++)
就會產生 100*100byte的記憶體洩漏.
2. 在某些時候,因為**上寫的有問題,會導致某些記憶體想**都收不回來,比如下面的**
temp1 = new byte[100];
temp2 = new byte[100];
temp2 = temp1;
這樣,temp2的記憶體位址就丟掉了,而且永遠都找不回了,這個時候temp2的記憶體空間想**都沒有辦法.
3. api函式應用不當,在windows提供api函式裡面有一些特殊的api,比如formatmessage. 如果你給它引數中有format_message_allocate_buffer,它會在函式內部new一塊記憶體buffer出來.但是這個buffer需要你呼叫localfree來釋放. 如果你忘了,那就會產生記憶體洩漏.
三: 檢查方法
一般的記憶體洩漏檢查的確是很困難,但是也不是完全沒有辦法.如果你用vc的庫來寫東西的話,那麼很幸運的是,你已經有了很多檢查記憶體洩漏的工具,只是你想不想用的問題了. visual c++的debug版本的c執行庫(c runtime library).它已經提供好些函式來幫助你診斷你的**和跟蹤記憶體洩漏. 而且最方便的地方是這些函式在release版本中完全不起任何作用,這樣就不會影響你的release版本程式的執行效率.
比如下面的例子裡面,有乙個明細的記憶體洩漏.當然如果只有這麼幾行**的話,是很容易看出有記憶體洩漏的.但是想在成千上萬行**裡面檢查記憶體洩漏問題就不是那麼容易了.
char * pstr = new char[5];
lstrcpy(pstr,"memory leak");
我們如果我們在debug版本的code裡面對堆(heap)進行了操作,包括malloc, free, calloc, realloc, new, 和 delete可以利用vc debug執行時庫中堆debug函式來做堆的完整性和安全性檢查. 比如上面的**,lstrcpy的操作明顯破壞了pstr的堆結構.使其溢位,並破壞了臨近的資料.那我們可以在呼叫lstrcpy之後的**裡面加入_crtcheckmemory函式._crtcheckmemory函式發現前面的lstrcpy使得pstr的堆結構被破壞,會輸出這樣的報告:
emory check error at 0x00372fa5 = 0x79, should be 0xfd.
memory check error at 0x00372fa6 = 0x20, should be 0xfd.
memory check error at 0x00372fa7 = 0x6c, should be 0xfd.
memory check error at 0x00372fa8 = 0x65, should be 0xfd.
damage:
after
normal
block (#41) at 0x00372fa0.
normal located at 0x00372fa0 is 5 bytes long.
它告訴說 pstr的長度應該時5個bytes,但是在5bytes後面的幾個bytes也被非法改寫了.提醒你產生了越界操作.
_crtcheckmemory的返回值只有true和false,那麼你可以用_asserte()來報告出錯資訊. 上面的語句可以換成 _asserte(_crtcheckmemory()); 這樣debug版本的程式在執行的時候就會彈出乙個警告對話方塊,如圖1,這樣就不用在執行時候一直盯著output視窗看了.這個時候按retry,就可以進入源**除錯了.看看問題到底出在**
圖1block, _crtisvalidpointer,_crtmemcheckpoint, _crtmemdifference, _crtmemdumpallobjectssince, _crtmemdumpstatistics, _crtsetallochook, _crtsetbreakalloc, _crtsetdbgflag,_crtsetdumpclient, _crtsetreportfile, _crtsetreporthook, _crtsetreportmode
這些函式全部都可以用來在debug版本中檢查記憶體的使用情況.具體怎麼使用這些函式就不在這裡說明了,各位可以去查查msdn.
在這些函式中用處比較大的,或者說使用率會比較高的函式是,_crtmemcheckpoint 設定乙個記憶體檢查點.這個函式會取得當前記憶體的執行狀態. _crtmemdifference 檢查兩種記憶體狀態的異同. _crtmemdumpallobjectssince 從程式執行開始,或者從某個記憶體檢查點開始dump出堆中物件的資訊. 還有就是_crtdumpmemoryleaks當發生記憶體溢位的時候dump出堆中的記憶體資訊. _crtdumpmemoryleaks一般都在有懷疑是記憶體洩漏的**後面呼叫,比如下面的例子
#include
#include
void main()
輸出:detected memory leaks! à提醒你,**有記憶體洩漏.
dumping objects ->
normal
block at 0x00372db8, 5 bytes long.
data: < > cd cd cd cd cd
object dump complete.
如果你雙擊包含行檔名的輸出行,指標將會跳到原始檔中記憶體被分配地方的行.
當無法確定那些**產生了記憶體洩漏的時候,我們就需要進行記憶體狀態比較. 在可疑的**段的前後設定記憶體檢查點,比較記憶體使用是否有可疑的變化.以確定記憶體是否有洩漏.為此要先定義三個_crtmemstate 物件來儲存要比較的記憶體狀態.兩個是用來比較,乙個用了儲存前面兩個之間的區別
_crtmemstate sh1,sh2,sh_diff;
char *pstr1 = new char[100];
_crtmemcheckpoint(&sh1); ->設定第乙個記憶體檢查點
char *pstr2 = new char[100];
_crtmemcheckpoint(&sh2); ->設定第二個記憶體檢查點
_crtmemdifference(&sh_diff, &sh1, &sh2); ->檢查變化
_crtmemdumpallobjectssince(&sh_diff); ->dump變化
如果你的程式中使用了mfc類庫,那麼記憶體洩漏的檢查方法就相當的簡單了.因為debug版本的mfc本身就提供一部分的記憶體洩漏檢查. 大部分的new 和delete沒有配對使用而產生的記憶體洩漏,mfc都會產生報告.這個主要是因為mfc過載了debug版本的new 和delete操作符. 並且對前面提到的api函式重新進行了包裝.在mfc類庫中檢查記憶體洩漏的class就叫 cmemorystate,它重新包裝了了_crtmemstate, _crtmemcheckpoint, _crtmemdifference, _crtmemdumpallobjectssince這些函式.並對於其他的函式提供了afx開頭的函式,供mfc程式使用 比如 afxcheckmemory, afxdumpmemoryleaks 這些函式的基本用法同上面提到的差不多. cmemorystate和相關的函式的定義都在afx.h這個標頭檔案中. 有個簡單的辦法可以跟蹤到這些函式的申明. 在vc中找到mfc程式**中下面的**, 一般都在x.cpp的開頭部分
#ifdef _debug
#define new debug_new
#undef this_file
static char this_file = __file__;
#endif
把游標移到debug_new上面 按f12,就可以進入afx.h中定義這些class和函式的**部分. vc中記憶體洩漏的常規檢查辦法主要是上面的兩種.當然這兩種方法只是針對於debug版本的heap的檢查.如果release版本中還有記憶體洩漏,那麼檢查起來就麻煩很多了.
4 .總結:
實際上heap的記憶體洩漏問題是相當的好查的.vc的提供的檢查工具也不太少,但是如果是棧出了什麼問題,恐怕就麻煩很多了. 棧出問題,一般不會產生記憶體洩漏,但是你的**的邏輯上很有可能會有影響.這個是最最痛苦的事情. 程式設計,就是小心,小心再小心而已.
很土 最後完成時間 2003-3-15 中午
記憶體洩漏檢測
一 記憶體洩漏 記憶體洩漏是程式設計中常常見到的乙個問題.記憶體洩漏往往會一種奇怪的方式來表現出來,基本上每個程式都表現出不同的方式.但是一般 最後的結果只有兩個,乙個是程式當掉.乙個是系統記憶體不足.還有一種就是比較介於中間的結果程式不會當,但是系統的反映時間明顯降低,需要定時的 reboot才會...
記憶體洩漏檢測
一 記憶體洩漏 記憶體洩漏是程式設計中常常見到的乙個問題.記憶體洩漏往往會一種奇怪的方式來表現出來,基本上每個程式都表現出不同的方式.但是一般最後的結果只有兩個,乙個是程式當掉.乙個是系統記憶體不足.還有一種就是比較介於中間的結果程式不會當,但是系統的反映時間明顯降低,需要定時的reboot才會正常...
記憶體洩漏檢測
當以前分配的一片記憶體不再需要使用或無法訪問時,但是卻並沒有釋放它,那麼對於該程序來說,會因此導致總可用記憶體的減少,這時就出現了記憶體洩漏memory leak。在程式設計實踐中,往往用到較多的是動態的記憶體分配,這樣在程式執行的時候分配記憶體,而不是在建立程序的時候就分配記憶體,這大大提高了記憶...