記憶體洩漏檢測

2021-04-13 12:48:05 字數 4466 閱讀 5009

一: 記憶體洩漏

記憶體洩漏是程式設計中常常見到的乙個問題. 記憶體洩漏往往會一種奇怪的方式來表現出來,基本上每個程式都表現出不同的方式. 但是一般 最後的結果只有兩個,乙個是程式當掉.乙個是系統記憶體不足. 還有一種就是比較介於中間的結果程式不會當,但是系統的反映時間明顯降低,需要定時的 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,就可以進入源**除錯了.看看問題到底出在**

圖1這些函式全部都可以用來在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的提供的檢查工具也不太少,但是如果是棧出了什麼問題,恐怕就麻煩很多了. 棧出問題,一般不會產生記憶體洩漏,但是你的**的邏輯上很有可能會有影響.這個是最最痛苦的事情. 程式設計,就是小心,小心再小心而已. 

記憶體洩漏檢測

一 記憶體洩漏 記憶體洩漏是程式設計中常常見到的乙個問題.記憶體洩漏往往會一種奇怪的方式來表現出來,基本上每個程式都表現出不同的方式.但是一般最後的結果只有兩個,乙個是程式當掉.乙個是系統記憶體不足.還有一種就是比較介於中間的結果程式不會當,但是系統的反映時間明顯降低,需要定時的reboot才會正常...

記憶體洩漏檢測

記憶體洩漏檢測 自己寫的 作者 很土 關鍵字 記憶體洩漏 記憶體 debug heap 堆 原作者姓名 很土 介紹簡單說明了一下沒有工具的情況如何運用vc庫中的工具來檢查 的記憶體洩漏問題 讀者評分 8 評分次數 2 正文記憶體洩漏檢測 一 記憶體洩漏 記憶體洩漏是程式設計中常常見到的乙個問題.記憶...

記憶體洩漏檢測

當以前分配的一片記憶體不再需要使用或無法訪問時,但是卻並沒有釋放它,那麼對於該程序來說,會因此導致總可用記憶體的減少,這時就出現了記憶體洩漏memory leak。在程式設計實踐中,往往用到較多的是動態的記憶體分配,這樣在程式執行的時候分配記憶體,而不是在建立程序的時候就分配記憶體,這大大提高了記憶...