一:背景
上一篇我們聊到了如何去找 熱點函數
,這一篇我們來看下當你的程序出現了 非托管內存泄漏
時如何去尋找可疑的代碼源頭,其實思路很簡單,就是在 HeapAlloc 或者 VirtualAlloc 時做 Hook 攔截,記錄它的調用棧以及分配的內存量, PerfView 會將這個 分配量 做成一個 權重
,最后可以根據 權重
高低來找到有問題的調用棧。
二:案例演示
為了方便講述,我們演示一個 Windows 的 Nt堆 內存泄漏,讓 C# 調用 C++ 代碼時故意泄漏內存,代碼如下:
#include?<iostream>extern?"C"
{_declspec(dllexport)?int?calc_size(int?size);
}int?calc_size(int?size)?{int*?buffer?=?new?int[size];return?2?*?size;
}
然后在 C# 中導入這個 C++ 的 dll。
internal?class?Program{[DllImport("ConsoleApplication2.dll",?CallingConvention?=?CallingConvention.Cdecl)]extern?static?int?calc_size(int?size);static?void?Main(string[]?args){for?(int?i?=?0;?i?<?int.MaxValue;?i++){var?size?=?calc_size(1000);Console.WriteLine($"i={i}");}}}
接下來把程序跑起來,再打開 Perfview,在 OS Heap Process
輸入框填入進程號19404,監控 15s然后 Start Collection
即可,這么做的目的時攔截 HeapAlloc
和 HeapFree
方法,截圖如下:

稍等 15s 之后,打開 Memory / Net OS Heap Alloc Stacks
選項卡。

接下來切到 CallTree
選項卡,清除掉 GroupPats
中的條件,觀察各自的調用棧,截圖如下:

從圖中的 inc %
列可以看到,calc_size
方法的 分配權重量
占 總分配量的 99.9%
,這就說明此方法有很大的嫌疑,最后就是查看源碼了哦。