我正在使用供应商提供的C ++ DLL,我用DLLImport
调用它来解析和处理包含许多对象类型的文件。
我需要在文件中的对象数量和内存使用量之间建立关联,以便(希望)能够防止有时发生的OutOfMemoryExceptions。
要更清楚我要测量的内容和原因:预计会出现内存不足异常,因为一些非常复杂的文件需要加载7gb的内存(由perfmon测量):它们是3D地图有时是巨大而错综复杂的建筑物,从墙壁到单独的螺钉和螺栓,包括外面的树木和每个房间的桌椅。
由于DLL可以并行加载多个映射(它位于Web服务器上并且进程是共享的),因此加载2x 7gb文件可以理解地在具有8GB RAM的机器上触发OutOfMemoryException。 然而,7gb是非常罕见的,大多数地图占用大约500mb,有些需要1到2GB。
我们真正需要的是不来查找内存泄漏(但是......),但能够在加载文件之前知道 它可能会有多少内存使用。因此,当用户尝试加载我们计算的文件时,可能需要大约2GB的RAM,而机器有1gb的空闲时间,我们会对此做些什么。从在Azure中启动新VM以防止用户工作,我们还不知道还有什么,但我们不能让DLL每次都崩溃整个服务器。
为了做到这一点,我想找出,例如,“DLL为每100个几何对象使用1mb内存”。
所以我有一堆要测试的文件(大约一百个),我想按顺序加载它们,测量本机DLL的内存使用情况(之前和之后),卸载文件,处理下一个文件。然后我得到一个包含所有数据的漂亮的CSV文件。
我已经尝试了System.Diagnostics.Process.GetCurrentProcess().VirtualMemorySize64
,但它只给了我当前的进程内存,但DLL似乎不在当前进程中,因为大多数度量给出0个字节(文件加载前后的差异) )。
我也试过GC.GetTotalMemory()
,但它并没有好多少,文件看起来都是1080字节。
private static void MeasureFilesMemoryUsage(string[] files) {
foreach (var file in files) {
var beforeLoad = MeasureMemoryUsage();
wrapper.LoadFile(file)
var afterLoad = MeasureMemoryUsage();
wrapper.Unload();
// save beforeLoad and afterLoad
}
}
private static long MeasureMemoryUsage() {
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
return System.Diagnostics.Process.GetCurrentProcess().VirtualMemorySize64;
}
我知道VMMAP或RedGate Ants Memory Profiler(或简称性能计数器)等工具,但这些不允许我将内存使用情况与特定的加载文件相匹配,我必须逐个加载文件,暂停程序,在工具中进行测量,并记下结果。不是我想对100个文件做的事情。
如何衡量.Net代码中特定C ++ DLL的内存使用情况?
答案 0 :(得分:0)
在阅读了@HansPassant评论之后,我将测试分成两个程序:一个加载文件,另一个读取第一个的内存测量值。
在这里,他们被清理,以删除其他措施(如我的json文件中的项目数)和结果保存。
“措施”计划:
public static void Main(string[] args) {
foreach (var document in Directory.EnumerateDirectories(JsonFolder)) {
MeasureMemory(document);
}
}
private static void MeasureMemory(string document) {
// run process
var proc = new Process {
StartInfo = new ProcessStartInfo {
FileName = "loader.exe",
Arguments = document,
WindowStyle = ProcessWindowStyle.Hidden,
UseShellExecute = false,
RedirectStandardOutput = true,
CreateNoWindow = true
}
};
proc.Start();
// get process output
var output = string.Empty;
while (!proc.StandardOutput.EndOfStream) {
output += proc.StandardOutput.ReadLine() + "\n";
}
proc.WaitForExit();
// parse process output
var processMemoryBeforeLoad = long.Parse(Regex.Match(output, "BEFORE ([\\d]+)", RegexOptions.Multiline).Groups[1].Value);
var processMemoryAfterLoad = long.Parse(Regex.Match(output, "AFTER ([\\d]+)", RegexOptions.Multiline).Groups[1].Value);
// save the measures in a CSV file
}
“装载机”程序:
public static int Main(string[] args) {
var document = args[0];
var files = Directory.EnumerateFiles(document);
Console.WriteLine("BEFORE {0}", MeasureMemoryUsage());
wrapper.LoadFiles(files);
Console.WriteLine("AFTER {0}", MeasureMemoryUsage());
wrapper.Unload();
return 0;
}
private static long MeasureMemoryUsage() {
// make sure GC has done its job
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
return System.Diagnostics.Process.GetCurrentProcess().VirtualMemorySize64;
}