java 記憶體洩漏排查_如何排查記憶體洩漏
阿新 • • 發佈:2020-12-16
技術標籤:java 記憶體洩漏排查valgrind 記憶體洩漏一個解決方案多個專案使用vld檢測記憶體洩漏
知其然並知其所以然,從基礎開始,我們深入觀察各種酷炫技術的內在實現
在我們寫一個龐大專案的時候,比如我們為公司寫一個面向具體業務的引擎核心的時候,我們並沒有什麼卵詳盡的開發計劃和設計,往往我們都是一邊設計,一邊想實現,需求還經常變化,這是無法避免的,就像是你去打副本,你只知道要把人家Boss收拾了才能拿到裝備,至於你每次去的時候組到了什麼隊友,怎麼收拾的Boss,那可能就千變萬化了。 從設計者的角度來看 這種開發流程是非常棒的
![3dd4f3fa8861bd5472b0b279c4a89b54.png](https://img.796t.com/res/2020/12-16/13/894c38feddc66a70201280c8477fc6e2.png)
![c824b706a0f979342bd037175aed5bbb.png](https://img.796t.com/res/2020/12-16/13/c32e9a6ef532cf809dd6b6f41a62a8ff.png)
![61645a9c8bd876344cb6f7be64ee440b.png](https://img.796t.com/res/2020/12-13/13/715e7951a2345478390ab2ed8771eb47.png)
![c6f6c3ec15fd2bdecf1933fc1de70405.png](https://img.796t.com/res/2020/12-16/13/1142c4674d23ee93850fb3d2de0d0932.png)
#ifdef_DEBUGinlinevoid*__cdecloperatornew(unsignedintsize,constchar*file,intline){};inlinevoid__cdecloperatordelete(void*p){};#endif
上面就是現階段的全部程式碼了,我們就過載了這倆函式,並且我們用#ifdef和#endif把它們框起來了,因為我們說了,我們本文介紹的是記憶體追蹤,不是記憶體池演算法。如果你實現了記憶體池演算法,那麼你的這個過載應該是一直開著的。記憶體池的好處咱們就不詳細的說了,總而言之,就是讓你的系統更加的穩定和可Debug。
由於我們還希望知道我們記憶體分配的時候,是哪個檔案的哪行程式碼分配的記憶體洩漏了,所以我們的使用了下面的巨集來進一步的封裝了new運算子,這樣一來,你就無需要改變你現有的程式碼,它們會自動的給自己新增上自己是在哪個地方初始化的記憶體塊。
#ifdef_DEBUG#define DEBUG_NEW new(__FILE__, __LINE__)#else#define DEBUG_NEW new#endif#define new DEBUG_NEW
現在我們來實現我們的new和delete函式,我們在初始化記憶體塊後,對它進行追蹤,在釋放記憶體塊之後,取消對它的追蹤,如此一來,程式執行結束之後,還處於追蹤狀態的記憶體塊就是沒被釋放的記憶體塊,也就是記憶體洩漏了。
#ifdef _DEBUGinlinevoid*__cdecloperatornew(unsignedintsize,constchar*file,intline){ void*ptr=(void*)malloc(size); AddTrack((DWORD)ptr, size, file, line); return(ptr);};inlinevoid__cdecloperatordelete(void*p){ RemoveTrack((DWORD)p); free(p);};#endif
下面的程式碼展示的就是追蹤記憶體塊和取消對記憶體塊追蹤的程式碼,我們會把所有的記憶體塊都串成一個連結串列。
typedef struct { DWORD address; DWORD size; char file[64]; DWORD line;} ALLOC_INFO;typedef list AllocList;AllocList *allocList;void AddTrack(DWORD addr, DWORD asize, const char *fname, DWORD lnum){ ALLOC_INFO *info; if(!allocList) { allocList = new(AllocList); } info = new(ALLOC_INFO); info->address = addr; strncpy(info->file, fname, 63); info->line = lnum; info->size = asize; allocList->insert(allocList->begin(), info);};void RemoveTrack(DWORD addr){ AllocList::iterator i; if(!allocList) return; for(i = allocList->begin(); i != allocList->end(); i++){ if((*i)->address == addr){ allocList->remove((*i)); break; } }};
最後這段程式碼就是在程式執行結束的時候去打印出來還沒有被釋放的記憶體塊的程式碼,這些記憶體塊就是記憶體洩漏的地方。由於我們之前記錄了每一塊記憶體是從哪裡分配出去的,所以我們很容易就知道,我們的程式碼是哪裡出現了記憶體洩漏。
voidDumpUnfreed(){ AllocList::iterator i; DWORD totalSize = 0;charbuf[1024]; if(!allocList)return; for(i = allocList->begin(); i != allocList->end(); i++) { sprintf(buf, "%-50s:\t\tLINE %d,\t\tADDRESS %d\t%d unfreed\n", (*i)->file, (*i)->line, (*i)->address, (*i)->size); OutputDebugString(buf); totalSize += (*i)->size; } sprintf(buf, "-----------------------------------------------------------\n"); OutputDebugString(buf); sprintf(buf, "Total Unfreed: %d bytes\n", totalSize); OutputDebugString(buf);};
故事的最後
我們為同學們介紹一個程式分析工具
這個工具的名字叫:valgrind
它的功能是自動檢測記憶體管理
以及執行緒BUG
官網地址如下:
http://www.valgrind.org/