重載全局new/delete實(shí)現(xiàn)內(nèi)存檢測(cè)下面介紹用重載new/delete運(yùn)算符的方式來(lái)實(shí)現(xiàn)一個(gè)簡(jiǎn)單的內(nèi)存泄露檢測(cè)工具,基本思想是重載全局new/delete運(yùn)算符,被檢測(cè)代碼調(diào)用new和delete運(yùn)算符時(shí)就會(huì)調(diào)用重載過(guò)的operator new和operator delete,在重載的operator new里和operator delete里記錄下內(nèi)存申請(qǐng)和釋放信息,從而判斷內(nèi)存使用情況。 下面一步步介紹它的實(shí)現(xiàn)! 1、 全局new/delete的重載 先看一下重載new/delete的規(guī)則: 重載的operator new的參數(shù)個(gè)數(shù)任意,但第一個(gè)參數(shù)必須是size_t類型的,返回值必須是void*。重載operator delete只允許有一個(gè)參數(shù),且是void*型。 當(dāng)然,不光要重載operator new 和 operator delete, 還要重載operator new [], operator delete [],更多operator new和operator delete重載的內(nèi)容參考《Effective C++》 重載的new/delete, new[]/delete[]代碼如下: void * operator new (size_t size){ if(0 == size){ return 0; } void *p = malloc(size); return p; }
void * operator new [](size_t size){ return operator new(size); }
void operator delete (void * pointer){ if(0 != pointer){ free(pointer); } }
void operator delete[](void * pointer){ operator delete(pointer); }
2、 用__FILE__, __LINE__記錄new的位置 為了找到內(nèi)存泄露的元兇,我要記錄下每一處new所在的文件名和所在行。于是再次重載了operator new: void * operator new (size_t size, const char* file, const size_t line); void * operator new [](size_t size, const char* file, const size_t line); 為了避免編譯時(shí)出現(xiàn)warning C4291(沒(méi)有與operator new(unsigned int,const char *,const unsigned int) 匹配的delete),又重載了 void operator delete (void * pointer, const char* file, const size_t line); void operator delete[](void * pointer, const char* file, const size_t line); 盡管我知道它沒(méi)用。 我想到了用系統(tǒng)提供的__FILE__和 __LINE__宏獲取當(dāng)前文件名與行號(hào),我試圖把__FILE__和 __LINE__直接填到operator new和operator new[]函數(shù)體里邊,然后把函數(shù)置成inline,結(jié)果都輸出的是重載operator new和operator new[]的文件和函數(shù)體printf函數(shù)所在行。然后又試了將operator new的缺省參數(shù)設(shè)為__FILE__和 __LINE__結(jié)果依然,于是想到了用宏定義。 先看看MFC里的做法,MFC為了調(diào)試方便,對(duì)new進(jìn)行了宏定義: #define new DEBUG_NEW #define DEBUG_NEW new(THIS_FILE, __LINE__)
這里我借用MFC的做法,我也用宏定義: void * operator new (size_t size, const char* file, const size_t line); void * operator new [](size_t size, const char* file, const size_t line); #define MC_NEW new(__FILE__, __LINE__) #define new MC_NEW
3、 將malloc/free 用new/delete替換 為了便于統(tǒng)計(jì)malloc/free信息,也用宏定義的方法處理: #define malloc(s) ((void*)new unsigned char[s]) #define free(p) (delete [] (char*)(p));
4、 在數(shù)據(jù)結(jié)構(gòu)里存儲(chǔ)內(nèi)存使用情況。 下面寫一個(gè)用于存儲(chǔ)new/delete中內(nèi)存信息的數(shù)據(jù)結(jié)構(gòu),可以使用鏈表,也可以使用哈希表,這里選用哈希表,寫一個(gè)CHash類。 代碼略。
5、 為了保證CHash在所有對(duì)象析構(gòu)執(zhí)行完之后再銷毀,應(yīng)該將CHash放在全局存儲(chǔ)區(qū),將其設(shè)成static類型,另外,如果有多個(gè)static,還需要注意放置的順序。
到這里這個(gè)簡(jiǎn)易的內(nèi)存泄露檢測(cè)工具完成了,但目前還不能用于多線程。
|
|