【发布时间】:2018-02-28 09:35:12
【问题描述】:
我正在使用供应商提供的 C++ DLL(我使用 DLLImport 调用它)来解析和处理包含许多对象类型的文件。
我需要在文件中的对象数量和内存使用之间建立关联,以便(希望)能够防止有时发生的 OutOfMemoryExceptions。
更新
为了更清楚我要测量的内容以及原因:预计会出现内存不足异常,因为一些非常复杂的文件需要高达 7gb 的内存来加载(由 perfmon 测量):它们是 3D 地图有时是巨大而复杂的建筑物,从墙壁到单独的螺钉和螺栓,包括外面的树木和每个房间的桌椅。
而且由于 DLL 可以并行加载多个映射(它在 Web 服务器上并且进程是共享的),加载 2x 7gb 文件可以理解地在具有 8gb 内存的机器上触发 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 的内存使用情况?
【问题讨论】:
-
DLL 不能分配进程外内存; DLL 中的代码在逻辑上是进程的一部分(因此,您无法区分每个 DLL 分配了多少内存,除非堆栈跟踪到分配函数)。 DLL 可以调用进程外 COM 服务器等,但这是不寻常的。如果进程分配内存,
VirtualMemorySize64应该会改变。也许包括一个简短的代码 sn-p 你正在测量的方式(和什么)。 (另外,PrivateMemorySize64可能是更好的衡量标准。) -
DllImport 将库加载到当前进程中一次 - 它不会卸载它(直到应用程序域死亡)。良好的 C++ 库在执行繁重的操作后不应该消耗额外的内存——所有资源都应该被它释放。它在运行过程中当然会消耗内存,但之后不会。所以不确定你到底想测量什么。
-
1080 字节非常小。如果库完全分配了任何内容,则可能无法从已分配的页面中检测到它,因此逐个文件工作不太可能为您提供任何东西。如果您真的想检测内存不足的情况来自何处,那么您最好 1) 导致 OOM 和 2) 获取内存转储并分析它以查看它的来源。例如,它可能是一个非常小的内存泄漏,需要持续数小时才能看到任何东西,而分析单个负载不会显示这一点。
-
@JeroenMostert :我添加了我正在做的精简代码示例。 @Evk:DLL 加载要在 3D 中操作的文件,因此它将文件(或者更确切地说,文件的表示)保存在内存中,直到进程退出或我告诉它“销毁”文件。在示例中的
LoadFile之后,我们通常调用Rotate、Zoom等。 -
@JeroenMostert 1080 bytes 实际上是完全错误的。 Perfmon 告诉我,我加载的一些文件使用 2gb 内存,其中大多数使用大约 500mb。我有另一个示例程序,它只加载一个文件并且从不释放它,我可以用它来拍摄内存快照并手动进行测量,但我真的,真的不想为一百个文件做这件事。我不是试图追踪内存泄漏,而是正常的内存使用情况,以将其与文件数据相关联。我会尝试在我的帖子中更好地解释。