1. 程式人生 > >C++檢測和定位記憶體洩漏的技巧

C++檢測和定位記憶體洩漏的技巧

在實際開發過程中專案中由於各方面原因,總是有人抱怨存在記憶體洩漏,系統長時間執行之後,可用記憶體越來越少,萇至導致了某些服務失敗。記憶體洩漏是最難發現的常見錯誤之一,因為除非用完記憶體或呼叫malloc失敗,否則都不會導致任何問題。實際上,使用C/C++這類沒有垃圾回收機制t的語言時,在如何正確處理釋放記憶體上會花費很長時間。如果程式執行時間足夠長,如後臺程序執行在伺服器上,只要伺服器不宕機就一立執行,一個小小的失誤也會對程式造成重大影響,如造
成某些關鍵服務失敗。

wikipedia中這樣定義記憶體洩漏在電腦科學中,記憶體洩漏指由於疏忽或錯誤造成程式未能釋放已經不再使用記憶體的情況。記憶體洩漏並非指記憶體在物理上的消失,而是應用程式分配某段記憶體後,由於設計錯誤,導致在釋放該段記憶體之前就失去了對該段記憶體的控制,從而造成了記憶體的浪費。最難捉摸也最難檢測到的錯誤之一是記憶體洩漏,即未能正確釋放以前分配的記憶體的bug。只發生一次小的記憶體洩漏可能不會被注意,但洩漏大量記憶體的程式或洩漏日益增多的程式可能會表現出各種徵兆從效能不良(並且逐漸降低)到記憶體完全用盡。更糟糕的是,洩漏的程式可能會用掉太多記憶體,以致另一個程式失敗,而使使用者無從查詢問題的真正根源。此外,即使無害的記憶體洩漏也可能是其他問題的徵兆。記憶體洩漏會因為減少可用記憶體的數量而降低計算機的效能。最終,在最糟糕的情況下,過多的可用記憶體被分配掉,導致全部或部分裝置停止正常工作,或者應用程式

崩潰。記憶體洩漏可能不嚴重,移至能夠用常規的手段檢測出來。在現代作業系統中,一個應用程式使用的常規記憶體在程式終止時被釋放。這表示一個短暫執行的應用程式中的記憶體洩漏不會導致嚴重後果。

在以下情下,記憶體洩漏會導致較嚴重的後果:
1.工程式執行後置之不理,時間久了消耗的記憶體越來越多(比如伺服器上的後臺任務,尤其是嵌入式系統中的後臺任務,這些任務執行後可能很多年內都置之不理);

2·新的記憶體被頻繁地分配,比如當顯示電腦遊戲或動畫視訊畫面時;

3.程式能夠請求未被釋放的記憶體(比如共享記憶體),移至是在程式終止的時候;

4.洩漏在作業系統內部發生,在系統關鍵驅動中發生;

5.記憶體非常有限,比如在嵌入式系統裝置中;

6.當運行於一個終止時記憶體並不自動釋放的作業系統(比如AmigaOS)之上,而一旦丟失只能通過重慶來恢復;

通過下面這個例子,來介紹如何檢測記憶體洩漏問題
#include «stdlib. h»
#include «iostream»
using namespace std
void GetMemory(char *p,int num)
{
//使用new也能夠檢測出來
P=(c har *) malloc(sizeof(char*) * num);
}

int main(int arge, char** argv)
{
char *str=NULL;
GetMemory(str, 100);
cout<<"Memory leak test!"<<endl;
//如果main中存在while迴圈呼叫GetMemow
//問題將變得很嚴重
/ /while(1){

//  GetMemory(...)

//} 

return o 
}

但是,實際開發中不可能這麼簡單,此程式只用於測試。
Windows平臺下的記憶體洩漏檢測方法。Windows平臺下Visual Studio偵錯程式和C執行時(CRT)庫為我們提供了檢測和識別記憶體洩漏的有效方法,原理大致如下記憶體分配要通過CRT在執行時實現,只要在分配記憶體和釋放記憶體時分別做好記錄工程式結束時對比分配記憶體和釋放記憶體的記錄就可以確定是不是有記憶體洩漏。在Visual Studio中啟用記憶體檢測的方法如下。

STEP1:在程式中包括以下語句:

#define_CRTDBG_MAP_ALLOC

#include<stdlib.h>

#include<crtdbg.h>

說明#include語句必須採用下文所示的順序,如果更改了順序,所使用的函式可能無法正常工作,

通過在程式碼中包括crtdbg.h,將malloc和free函式對映到對應除錯版本,即_malloc_dbg呂和free_dbg中,這兩個函式將跟蹤記憶體分配和釋放。此對映只在除錯版(當定義_DEBUG時)中發生,釋出版使用普通的malloc和free函式。

#define語詞將CRT堆函式的基版本對映到對應的。Debug。版本,並非絕對需要該語詞但如果沒有該語詞,記憶體洩漏轉儲包含的有用資訊將較少。

STEP2:在添加了上述語句之後,可以通過在程式中包括下述語(通常應恰好放在程式退出位置之前)來轉儲記憶體洩漏資訊:
_CrtDumpMemowLeaJcso
按照上面的步驟進行,完整的程式碼應該是這樣的

#define_CRTDBG_MAP_ALLOC
#include <stdlib. h>
#include <crtdbg. h>
#include <iostream>
using namespace std;
void GetMemory(char * p, int num)
{
p=(c har *) malloc (sizeof(char) * num);
}
int maintint arge, char** argv)
{
char *str=NULL;
GetMemory(str, 100);
cout<<"Memory leak test!"<<endl;
_CrtDumpMemoryLeaks();
return 0;
}

當在偵錯程式下執行程式時,_CrtDumpMemoryLeaks將在"輸出"視窗中顯示記憶體洩漏資訊。記憶體洩露資訊下所以:

Detected memory leaks!
Dumping objects->
c\users \liuguang \ documentAvisual studio 201o \ projectsMemory \ memory. cpp (14):{1159} normal block at O×008F6598, 1 00 bytes long.
Data<           > CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD
Object dump complete.

程式"[4904] Memoly.exe本機"已退出,返回值為0 (0×0)。