C++ 程式記憶體洩漏檢測方法

發表於2017-01-05

一、前言

在Linux平臺上有valgrind可以非常方便的幫助我們定位記憶體洩漏,因為Linux在開發領域的使用場景大多是跑伺服器,再加上它的開源屬性,相對而言,處理問題容易形成“統一”的標準。而在Windows平臺,伺服器和客戶端開發人員慣用的除錯方法有很大不同。下面結合我的實際經驗,整理下常見定位記憶體洩漏的方法。

注意:我們的分析前提是Release版本,因為在Debug環境下,通過VLD這個庫或者CRT庫本身的記憶體洩漏檢測函式能夠分析出記憶體洩漏,相對而言比較簡單。而伺服器有很多問題需要線上上併發壓力情況下才出現,因此討論Debug版除錯方法意義不大。

二、物件計數

方法:在物件構造時計數++,析構時–,每隔一段時間列印物件的數量

優點:沒有效能開銷,幾乎不佔用額外記憶體。定位結果精確。

缺點:侵入式方法,需修改現有程式碼,而且對於第三方庫、STL容器、指令碼洩漏等因無法修改程式碼而無法定位。

三、過載new和delete

方法:過載new/delete,記錄分配點(甚至是呼叫堆疊),定期列印。

優點:沒有看出

缺點:侵入式方法,需將標頭檔案加入到大量原始檔的頭部,以確保過載的巨集能夠覆蓋所有的new/delete。記錄分配點需要加鎖(如果你的程式是多執行緒),而且記錄分配要佔用大量記憶體(也是佔用的程式記憶體)。

四、Hook Windows系統API

方法:使用微軟的detours庫,hook分配記憶體的系統Api:HeapAlloc/HeapRealloc/HeapFree(new/malloc的底層呼叫),記錄分配點,定期列印。

優點:非侵入式方法,無需修改現有檔案(hook api後,分配和釋放走到自己的鉤子函式中),檢查全面,對第三方庫、指令碼庫等等都能統計到。

缺點:記錄記憶體需要佔用大量記憶體,而且多執行緒環境需要加鎖。

五、使用DiagLeak檢測

微軟出品的記憶體洩漏分析工具,原理同hookapi方式。配合LDGraph視覺化展示記憶體分配資料,更方便查詢洩漏。

  1. 在IDE工程選項裡面配置Release版本也生成除錯資訊,釋出時,將pdb檔案和exe檔案一起釋出。

2.程式執行後,開啟LeakDiag,設定Symbol path

3.定期Log下目標程式的記憶體分配情況,通過LDGraph列印分配增長情況,來發現記憶體洩漏。

優點:同hookapi方法,非侵入式修改,無需做任何程式碼改動。跟蹤全面。視覺化分析堆疊一覽無餘!

缺點:對效能有影響,hook分配加鎖,遍歷堆疊。但是不會佔用目標程式的自身記憶體。

六、總結

對於線上生產環境,建議大物件用計數來判斷,定位快速準確,幾乎無效能開銷。在對外測試階段,使用LeakDiag輔助分析,因為此時併發壓力還不是太大,效能開銷還是可以承受。線上上大規模應用階段,通過HookApi的方法,結合GM指令控制部分時間段的檢測,這樣可以把對玩家的影響(伺服器效能下降導致延遲)降到最低。

以上方法,我將後續的部落格中逐一詳細介紹,文中提到到detours庫和LeakDiag工具,想了解的朋友,可以上codeprojet上搜尋下相關介紹,如果要上google查詢資料,也可以上這裡。如果大家有新方法也可留言討論,我們共同完善這一系列的介紹文章。

相關文章