【问题标题】:Extremely high rates of paging active memory to disk but low constant memory usage将活动内存分页到磁盘的速率非常高,但持续内存使用率很低
【发布时间】:2012-11-25 09:31:24
【问题描述】:

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

我正在开发一个程序来处理从硬盘加载的大量图像。 它从每张图像中生成一些数据,我将其保存在列表中。对于每 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 的答案,因为它得到了很好的解释,而且他似乎做了很多工作来向像我这样的新人解释原因:)

【问题讨论】:

  • 您可以尝试禁用文件缓存并重新测试以查看是否有差异。 technet.microsoft.com/en-us/sysinternals/bb897561
  • 会不会是图像是使用内存映射文件读取的?如果是,那么大量的页面错误是例外行为,因为这就是有效读取图像的方式。
  • @JasonD 尝试将最大大小设置为非常低的值,但当前大小超出了它。并且程序的性能没有变化,但 Windows 确实表现得很奇怪:)
  • @Codo 据我所知,图像不是内存映射的。只是放在硬盘文件夹中的普通图片。
  • @AndersJørgensen:内存映射是一种用于读写文件的技术,而不是一种特殊类型的文件。它可以用任何文件来完成。您使用什么函数或库来读取文件?

标签: c# memory-management pagefile


【解决方案1】:

更新了更多信息

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

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

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

你可能想看看这个。

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

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

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

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

现在,查看Emgu.CV Image code,它在内部使用Image 类来获取图像位 - 所以这是通过函数 GdipLoadImageFromFile (Second entry on this index) 启动 GDI+ 来解码图像(使用系统资源,加上潜在的大字节数组) - 然后将数据复制到包含实际 RGB 值的未压缩字节数组中。

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

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

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

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

【讨论】:

  • 感谢您的帮助。这些图像每个大约 300 KB,我用 EMGU(C# 的 OpenCV)加载它们,所以我不知道底层结构。但我访问图像像素,所以字节必须以某种方式访问​​。
  • @AndersJørgensen 已更新 - 对您来说并没有什么不同的结论,但还有更多细节。
  • 我尝试删除图像处理代码,似乎分页与加载文件密切相关。我很想知道是否需要找到修复程序或只是购买额外的磁盘来拆分数据和页面文件。谢谢你的回答。
【解决方案2】:

但是,要确定哪个进程直接负责分页或为什么要确定并不总是那么容易。

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

功能,而不是错误。

【讨论】:

    猜你喜欢
    • 2011-08-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多