如何檢查記憶體洩露

2021-04-13 21:46:29 字數 4517 閱讀 6570

前一段時間寫了一些**,自以為速度和效率都還不錯,測試執行了一段時間,發現

程式總會在中途死掉,仔細查查,原來是記憶體洩露的原故。看來寫程式還真是個細活,以後在這方面要加強。

下面是我從網上搜到的檢查記憶體洩露的文章,還比較有用,牛人真是無處不在啊,以後有問題要多動手從網上找原因。

如何檢查記憶體洩露問題[**]

簡單說明了一下沒有工具的情況如何運用vc庫中的工具來檢查**的記憶體洩漏問題。

一: 記憶體洩漏

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

有乙個很簡單的辦法來檢查乙個程式是否有記憶體洩漏。就是是用windows的任務管理器(task manager)。執行程式,然後在任務管理器裡面檢視 「記憶體使用」和」虛擬記憶體大小」兩項,當程式請求了它所需要的記憶體之後,如果虛擬記憶體還是持續的增長的話,就說明了這個程式有記憶體洩漏問題。 當然如果記憶體洩漏的數目非常的小,用這種方法可能要過很長時間才能看的出來。

當然最簡單的辦法大概就是用compuware的boundchecker 之類的工具來檢測了,不過這些工具的**對於個人來講稍微有點奢侈了。

如果是已經發布的程式,檢查是否有記憶體洩漏是又費時又費力。所以記憶體洩漏應該在code的生成過程就要時刻進行檢查。

二: 原因

記憶體洩漏產生的原因一般是三種情況:

分配完記憶體之後忘了**;

程式code有問題,造成沒有辦法**;

某些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.

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

vc記憶體洩露檢查

mfc檢測記憶體洩露是最方便的,只要在需要檢測的cpp檔案開始包含 ifdef debug define new debug new endif 就可以了。這是通過過載new操作符,在debug時可以在output中輸出記憶體洩露的位置。非mfc中檢測記憶體洩漏需要加上 ifdef debug de...

如何檢查C 中的記憶體洩露

如何檢查c 中的記憶體洩漏 記憶體洩漏是程式設計中常常見到的乙個問題,我所遇過的原因有兩個 1.分配完記憶體後忘記 2.有問題,造成想 卻無法 例如 int p newint p new int p指標修改,原來申請記憶體的位址沒有記錄下來,於是無法釋放 下面介紹如何檢查記憶體洩漏 1.包含標頭檔案...

記憶體洩露檢查函式 mtrace

c語言中乙個malloc呼叫與乙個free呼叫對應出現。當專案足夠大的時候,我們就很容易忘記free記憶體,或者重複free記憶體。在一般linux發行版中,有一些自帶的記憶體檢查工具可以幫助我們去檢查對手動分配的記憶體的free情況,其中的乙個工具就是mtrace。使用mtrace之前需要在c原始...