c/c++程式給某些程式設計師的幾大印象之一就是記憶體自己管理容易洩漏容易崩,筆者曾經在乙個產品中使用c語言開發維護部分模組,只要產品有記憶體洩漏和崩潰的問題,就被甩鍋「我的程式是c#開發的記憶體都是託管的,c++那邊也沒有記憶體(庇護其好友),肯定是c這邊的問題」(話說乙個十幾年的程式設計師還停留在語言層面不覺得有點low嗎),筆者畢業不到一年,聽到此語心裡一萬頭草泥馬奔騰而過,默默地修改了程式,注意不是修改bug(哈哈),而是把所有malloc和free都替換成了自定義巨集malloc和free,debug版本所有記憶體分配釋放都打了日誌,程式結束自動報告類似「core memory leaks: 位元組數」,此後記憶體洩漏的問題再也沒人敢甩過來了。語言僅僅是個工具,人心是大道。
c語言應用程式一般使用malloc和free兩個函式分配和釋放記憶體,對它們做記憶體洩漏檢測還是很好想到完美方案的。所謂的完美:1)當記憶體洩漏時能迅速定位到是哪一行**分配的;2)使用簡單與原先無異;3)release時或者不需要除錯記憶體的時候,仍然使用原生態函式,不影響效率。
1#ifdef debug_memory
2#define malloc(size) mallocdebug(__file__, __line__, size)
3#define free(p) freedebug(__file__, __line__, p)
4#else
5#define malloc(size) malloc(size)
6#define free(p) free(p)
7#endif89
#ifdef debug_memory
10#define mem_op_malloc 1
11#define mem_op_free 0
1213
void logmemory(const
char* file, int line, void* p, int
operation, size_t size);
1415
void* mallocdebug(const
char* file, int
line, size_t size)
1621
22void freedebug(const
char* file, int line, void*p)
23
2728
void logmemory(const
char* file, int line, void* p, int
operation, size_t size)
2934
35void
detectmemoryleaks()
3639
40#endif
4142
void
program()
43
c語言應用程式中的上述記憶體洩漏檢測方案至此完美收官,記錄分配序號,也可以向crtsetbreakalloc那樣除錯記憶體洩漏哦。
近期在跟蹤c++專案的記憶體洩漏,專案包含多個工程(1個exe+多個自開發dll+多個第三方dll)。
1.首先考慮的第乙個方案是利用crtdbg。踩得第乙個坑是記得看下工程配置執行時庫選項用debug版本(/mtd或/mdd),否則無效。非mfc程式報不出可疑洩漏記憶體的檔名及行號,要在整個程式所有使用new的檔案中包含"#define new new(_normal_block, __file__, __line__)"的巨集定義。對於單個工程程式而言除錯比較簡單方便;對於多個dll尤其是有第三方庫時,/mtd配置下要非常小心,/mdd配置要好很多,但實際中使用crtdbg除錯還是偶爾會崩在系統底層記憶體分配的地方,出現的問題不在個人解決能力之內,放棄了。
2.其次的第二個方案,考慮自己過載operator new和operator delete,當然是要過載operator new(size_t size, const char* file, int line)這個版本才能在洩漏時定位到行號。同樣也是要所有使用new的檔案中包含"#define new new( __file__, __line__)"的巨集定義。問題是雖然可以過載operator delete(void* p, const char* file, int line)這個版本,但是這個版本只會在placement new失敗時才會呼叫,正常時候還是呼叫的operator delete(void* p)版本,所以還需要過載operator delete(void* p)版本,問題是沒有過載的系統內建的operator new(size_t size)版本分配的所有記憶體也會走使用者過載後的operator delete(void* p)版本,不配對,一起把operator new(size_t size)也過載了。
第二個方案的另外乙個問題是程式要包含巨集"#define new new( __file__, __line__)",但第三方庫標頭檔案中有placement new的用法new(pointer)classa(),專案大一點頭檔案順序不好調,編譯失敗。還有就是這個方案實踐中(多dll全部設定的相同的執行時庫配置)也在系統底層分配記憶體的方法崩潰過,也可能是個人在**的處理有問題,總之不再考慮前兩個方案了,打算在應用層做處理。
3.最後確定在最上層想方案,首先c++不能自定義操作符,否則就能定義乙個操作符a* pa = debugnew a(1, 2)了。巨集不能有空格只能考慮函式debugnew(a, 1, 2)了。下面上方案。
所有要分配或釋放記憶體的檔案中包含debugmemory.h標頭檔案(偽**):
1//檔名:debugmemory.h23
#ifdef debug_memory
4#define new(t, ...) debugnew(__file__, __line__, __va_args__)
5#define del(p) debugdelete(__file__, __line__, p)
6#define new_array(t, size) debugnewarray(__file__, __line__, size)
7#define del_array(p) debugdeletearray(__file__, __line__, p)
8#else
9#define new(t, ...) new t(__va_args__)
10#define del(p) delete(p)
11#define new_array(t, size) new t[size]
12#define del_array(p) delete p
13#endif
1415
#ifdef debug_memory
1617 template
18 t* debugnew(const
char* file, int line, args&&... args)
1924
25 template
26void debugdelete(const
char* file, int line, t*p)
2731
32 template
33 t* debugnewarray(const
char* file, int
line, size_t size)
3439
40 template
41void debugdeletearray(const
char* file, int line, t*p)
4246
47void
detectmemoryleaks()
4851
52#endif
使用debugmemory.h標頭檔案:
1//檔名:main.cpp
23 #include "
debugmemory.h"4
5classa6
9 a(int a, int
b):m_a(a), m_b(b){}
10private:11
intm_a;
12int
m_b;13}
1415
intmain()
16
1.c語言應用程式的記憶體洩漏解決方案:完美。
2.c++語言應用程式的記憶體洩漏解決方案
優點:沒有改變預設的operator new和operator delete行為,畢竟危險。
優點:實用性通用性強,完全在應用程式設計師的控制範圍內。因為在應用層,不管什麼版本都可以檢測記憶體洩漏,不用考慮跨dll呼叫產生的問題。
不足:寫法習慣改變,原來是new a(1,2),要寫成new(a, 1, 2),如果c++能實現自定義操作符,那麼方案就完美了。
C 程式記憶體洩漏檢查
一 在windows平台上面 以前我都是用purify,因為沒有正版的,很是麻煩,後來我開始用windows自帶的umdh,也很好用 摘要一下步驟如下 注 得先把gflags和umdh的路徑加入到path中,預設為 c program files x86 windows kits 8.1 debug...
C C 記憶體洩漏檢查之經驗
c程式中最可怕的事情就是碰到記憶體洩漏或者記憶體錯誤,特別是對於大型的專案而言要去查乙個小小的記憶體洩漏可要花不少功夫的。目前已經有很多這方面的工具,比較著名的如rational purify,不過purify對linux的支援比較少,而且有一種洩漏是由於執行過程中不斷增長但是在程式結束的時候釋放的...
C C 程式記憶體洩漏檢測
c c 程式記憶體洩漏檢測 摺疊 1.包含標頭檔案和定義 define crtdbg map alloc include include 如果定義了 crtdbg map alloc,列印出來的是檔名和行數等更加直觀的資訊。2.方法一 在程式入口寫幾個語句 int tmpflag crtsetdbg...