11

正如标题所述,我遇到了页面文件活动高的问题。

我正在开发一个处理大量图像的程序,它从硬盘驱动器加载。它从每张图像中生成一些数据,我将其保存在列表中。对于每 3600 张图像,我将列表保存到硬盘中,其大小约为 5 到 10 MB。它以尽可能快的速度运行,因此它最多使用一个 CPU 线程。

该程序工作,它生成它应该生成的数据,但是当我在 Visual Studio 中分析它时,我收到一条警告说:DA0014: Extremely high rates of paging active memory to disk

根据任务管理器,该程序的内存消耗约为 50 MB,似乎很稳定。当我运行该程序时,我在 4 GB 中剩下大约 2 GB,所以我想我并没有用完 RAM。 我的程序的内存使用情况http://i.stack.imgur.com/TDAB0.png

DA0014 规则描述说“例如,每秒输出的页数通常远大于每秒的页写入数。因为每秒输出的页数还包括系统文件缓存中更改的数据页。但是,它不是总是很容易确定哪个进程直接负责寻呼或为什么。”

这是否意味着我收到此警告仅仅是因为我从硬盘驱动器中读取了很多图像,还是其他原因?不太确定我在寻找什么样的错误。

编辑:链接到插入的图像。

EDIT1:图像大小约为 300 KB。在加载下一个之前,我会先处理每个。

更新:从实验看起来像分页来自只是加载大量文件。由于我不是 C# 或底层 GDI+ API 方面的专家,我不知道哪个答案最正确。我选择了 Andras Zoltans 的回答,因为它得到了很好的解释,而且他似乎做了很多工作来向像我这样的新人解释原因:)

4

2 回答 2

4

更新以下更多信息

您的应用程序的工作集可能不是很大 - 但是虚拟内存大小呢?分页可能因此而发生,而不仅仅是因为它的物理大小。请参阅在 Windows 8 上运行的 VS2012的Process Explorer的屏幕截图:

VS 2012 内存

在任务管理器上?显然,同一进程的私有工作集是 305,376Kb。

我们可以从中得出 a) 任务管理器不一定是可信的; b) 就操作系统而言,应用程序在内存中的大小比我们想象的要复杂得多。

你可能想看看这个。

分页几乎肯定是因为您对文件所做的事情,而最终数字高几乎肯定是因为您正在处理的文件数量。一个简单的测试是对不同数量的文件进行试验,并在这些文件旁边生成一个最终分页图的数据集。如果文件数量导致分页,那么您将看到明显的相关性。

然后取出您所做的任何处理(但保持图像加载)并再次比较 - 请注意差异。

然后完全删除图像加载代码——注意区别。

显然,当您删除图像加载时,您会看到最大的故障下降。

现在,查看Emgu.CV 图像代码,它在Image内部使用类来获取图像位 - 所以这是通过函数 GdipLoadImageFromFile (此索引上的第二个条目)启动 GDI+来解码图像(使用系统资源,加上可能大字节数组) - 然后将数据复制到包含实际 RGB 值的未压缩字节数组。

该字节数组使用(也被andGCHandle.Alloc包围)分配,以创建一个固定字节数组来保存图像数据(未压缩)。现在我不是 .Net 内存管理方面的专家,但在我看来,即使每个文件都是按顺序加载而不是并行加载的,我们也有可能在这里产生堆碎片。GC.AddMemoryPressureGC.RemoveMemoryPressure

我不知道这是否导致硬分页。但似乎很有可能。

特别是图像的内存表示可以专门针对显示而不是原始文件字节。因此,例如,如果我们谈论的是 JPEG,那么 300Kb 的 JPEG 在物理内存中可能会大得多,具体取决于其大小。例如,一个 1027x768 的 32 位图像是 3Mb - 每个图像被分配两次,因为它被加载(第一次分配)然后复制(第二次分配)到 EMGU 图像对象中,然后再被处置。

但是您必须问自己是否有必要找到解决问题的方法。如果您的应用程序不消耗大量物理 RAM,那么它对其他应用程序的影响就会小得多;如果有足够的物理内存,一个进程大量访问页面文件不会对另一个没有影响的进程产生严重影响。

于 2012-12-07T09:32:58.510 回答
1

但是,要确定哪个进程直接负责分页或原因并不总是容易的。

魔鬼就在那张逃避纸条里。位图使用内存映射文件从包含像素数据的文件映射到内存中。这是避免直接在 RAM 中读取和写入数据的有效方法,您只需为使用的内容付费。使文件与 RAM 保持同步的机制是分页。因此,如果您处理大量图像,则不可避免地会看到很多页面错误。您使用的工具不够聪明,无法知道这是设计使然。

功能,而不是错误。

于 2012-12-07T14:31:59.393 回答