从 C# 代码测量本机 DLL 内存使用情况
Measure native DLL memory usage from c# code
我正在使用供应商提供的 C++ DLL,我用 DLLImport
调用它来解析和处理包含许多对象类型的文件。
我需要在文件中的对象数量和内存使用之间建立关联,以便(希望)能够防止有时发生的 OutOfMemoryExceptions。
更新
为了更清楚地说明我要测量的内容和原因:内存不足异常是预料之中的,因为一些非常复杂的文件需要占用高达 7gb 的内存来加载(由 perfmon 测量):它们是有时巨大而复杂的建筑物的 3D 地图,从墙壁到各个螺丝和螺栓,包括外面的树木和每个房间的桌椅。
并且由于 DLL 可以并行加载多个地图(它在网络服务器上并且进程是共享的),加载 2x 7gb 文件可以理解地在具有 8gb RAM 的机器上触发 OutOfMemoryException。
不过7gb的还是比较少见的,大部分地图都在500mb左右,有的1~2gb。
我们真正需要的是不是发现内存泄漏(还...),而是能够在加载文件之前知道[=42] =] 它可能会使用多少内存。因此,当用户尝试加载一个文件时,我们计算可能需要大约 2gb 的 RAM,而机器有 1gb 空闲,我们会做一些事情;从在 Azure 中启动一个新的 VM 到阻止用户工作,我们还不知道是什么,但我们不能让 DLL 每次都让整个服务器崩溃。
为了做到这一点,我想找出,例如,"the DLL uses 1mb of memory for each 100 geometry object"。
所以我有一堆文件要测试(大约一百个),我想按顺序加载它们,测量原生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 的内存使用情况?
阅读@HansPassant 评论后,我将我的测试分为 2 个程序:一个加载文件,一个读取第一个程序的内存测量值。
在这里,清理它们以删除其他措施(例如我的 json 文件中的项目数)和结果保存。
"measures" 程序:
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
}
和 "loader" 程序:
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;
}
我正在使用供应商提供的 C++ DLL,我用 DLLImport
调用它来解析和处理包含许多对象类型的文件。
我需要在文件中的对象数量和内存使用之间建立关联,以便(希望)能够防止有时发生的 OutOfMemoryExceptions。
更新
为了更清楚地说明我要测量的内容和原因:内存不足异常是预料之中的,因为一些非常复杂的文件需要占用高达 7gb 的内存来加载(由 perfmon 测量):它们是有时巨大而复杂的建筑物的 3D 地图,从墙壁到各个螺丝和螺栓,包括外面的树木和每个房间的桌椅。
并且由于 DLL 可以并行加载多个地图(它在网络服务器上并且进程是共享的),加载 2x 7gb 文件可以理解地在具有 8gb RAM 的机器上触发 OutOfMemoryException。
不过7gb的还是比较少见的,大部分地图都在500mb左右,有的1~2gb。
我们真正需要的是不是发现内存泄漏(还...),而是能够在加载文件之前知道[=42] =] 它可能会使用多少内存。因此,当用户尝试加载一个文件时,我们计算可能需要大约 2gb 的 RAM,而机器有 1gb 空闲,我们会做一些事情;从在 Azure 中启动一个新的 VM 到阻止用户工作,我们还不知道是什么,但我们不能让 DLL 每次都让整个服务器崩溃。
为了做到这一点,我想找出,例如,"the DLL uses 1mb of memory for each 100 geometry object"。
所以我有一堆文件要测试(大约一百个),我想按顺序加载它们,测量原生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 的内存使用情况?
阅读@HansPassant 评论后,我将我的测试分为 2 个程序:一个加载文件,一个读取第一个程序的内存测量值。
在这里,清理它们以删除其他措施(例如我的 json 文件中的项目数)和结果保存。
"measures" 程序:
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
}
和 "loader" 程序:
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;
}