基本情况
最近在做的一款程序,长时间运行总会出现莫名的问题。有时是自动关闭,有时程序报错,有时调用的dll异常……
提出假设——dll内存泄漏
由于开始与C++组合作时,使用其提供的dll出现过数据读写时异常(内存操作异常),于是怀疑他们提供的dll有内存泄漏。于是想通过日志或其它方法来确认这个猜测。
如何验证是C++ dll的问题?
通过记录当前Process的Memory情况,确认在调用dll时内存的基本情况,然后与不调用dll的内存情况进行比对,基本就能确认到底是不是dll的内存操作有问题。
日志数据分析
记录进程内存情况与电脑内存运行情况
以下为记录内存状况的Function:
private static void MemoryLog()
{
Task.Run(async () =>
{
string appName = typeof(App).Namespace;
var mb = 1024 * 1024;
while (true)
{
Process currentProcess = Process.GetCurrentProcess();
var working = currentProcess.PagedMemorySize64;
await Task.Delay(1000);
NlogHelper.Logger.Trace($"MemoryLog Working Set: {currentProcess.WorkingSet64 / mb} MB, PeakWorking Set: {currentProcess.PeakWorkingSet64 / mb} MB, Private Memory: {currentProcess.PrivateMemorySize64 / mb} MB, PagedMemory: {currentProcess.PagedSystemMemorySize64 / mb}MB, PeakPagedMemory:{currentProcess.PeakPagedMemorySize64 / mb}MB");
NlogHelper.Logger.Trace($"MemoryLog {Performance.GetMemInfo()}");
}
});
}
上述代码中,working memory为进程分配的物理内存,private memory为进程的专用内存(此为最关键,虚拟内存),详细参考API:Process 类 (System.Diagnostics) | Microsoft Learn
下述为Performance中的GetMemInfo方法:
public static string GetMemInfo()
{
MEMORY_INFO mi = GetMemoryStatus();
return string.Format(", \t\t\t{0},{1:f0}%", FormatSize(mi.ullTotalPhys - mi.ullAvailPhys), mi.dwMemoryLoad);
}
/// <summary>
/// 获得当前内存使用情况
/// </summary>
/// <returns></returns>
public static MEMORY_INFO GetMemoryStatus()
{
MEMORY_INFO mi = new MEMORY_INFO();
mi.dwLength = (uint)Marshal.SizeOf(mi);
GlobalMemoryStatusEx(ref mi);
return mi;
}
[DllImport("kernel32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool GlobalMemoryStatusEx(ref MEMORY_INFO mi);
注意:在记录日志时最好记录为一行,同时数据之间以空格或逗号或tab分离等分隔符分离,以方便数据分析时在表格中使用分隔符进行分列统计。
日志图表化
通过日志记录发现,专用内存在不断增长:
也就是说一定是存在内存泄漏了。
而在不调用dll时运行50次的内存情况则如下:
也就是说在程序运行期间内C#内存使用情况是基本稳定的,不会出现不断增长的情况。
以上基本可以确认是C++的dll出现了问题。