12

我读到了内存限制

我有一个应用程序可以处理需要流式传输的巨大图像。就像在单帧视频处理中一样。该应用程序有大约 40 个插件,每个插件都可以包含数据库、图像处理和 WPF GUI。

该应用程序还有 2 个使用较旧的 DotNet Winforms 的插件。

除了应用程序在 RAM 中超过 1.2GB 之外,一切都运行良好。然后在插件中分配新内存的不寻常位置上,我收到“内存不足异常”。

我正在开发一个编译为 32 位的 64 位系统。我不知道该做什么以及如何寻找任何故障。

有限制还是我可以抓住它们?

4

3 回答 3

20

编写一个消耗所有可用虚拟内存空间的 32 位程序是非常困难的。您将在 2 GB 以下碰壁,首先用完的是一块足够大以适应请求大小的虚拟内存。您只能通过小分配来达到 2GB 的限制,小到足以容纳孔。

在操作位图的程序中,这堵墙很早就出现了。他们可以消耗大量的 VM 来存储位图像素,并且它需要是一个连续的分配。它们存储在一个array,而不是一个tree。这是一种非托管内存分配,典型的 .NET 内存分析器往往无法向您展示问题。

对于地址空间碎片,您无法做任何合理的事情,应该可以消耗所有可用 VM 的想法是错误的。editbin.exe通过在构建后事件中运行并使用其/LARGEADDRESSAWARE命令行选项,您可以在 64 位操作系统上获得更多喘息空间。这允许该进程使用可用的 4 GB 的 VM,这是一个特定于 64 位版本的 Windows 的选项,并且可能因为 Windows 不需要上面的 2 GB。当然,将平台目标更改为 AnyCPU 是获得大量虚拟内存的快速简便的方法。

于 2012-06-08T13:37:41.083 回答
0

为了变得更具确定性,您应该编写一些集成测试来检查您的内存最终在哪里。您现在可以使用WMemoryProfiler来完成。我会首先加载 1500x1500 大小的图像,清理所有内容,然后将所有对象标记为已知。然后我会重新加载大图像并检查分配了哪些新对象,并仔细查看其中有多少以及谁拥有它们。

您说使用了许多外部模块。也许你应该因为不明智地使用内存而放弃其中的一些,并用更好的东西替换它们。现在你可以检查了。

如果您达到限制,您仍然可以卸载一些图像并按需加载它们,如果您和您的插件确实支持惰性结构,例如IEnumerable<Image>您作为提供者可以决定何时加载图像以及将其保存在缓存中多长时间,直到您摆脱引用以帮助释放一些内存。

[Test]
public void InstanceTracking()
{
   using (var dumper = new MemoryDumper())  // if you have problems use to see the debugger windows true,true))
   {
      TestWith1500x1500();
      dumper.MarkCurrentObjects();
      TestWith3000x3000();
      ILookup<Type, object> newObjects = dumper.GetNewObjects()
                                               .ToLookup( x => x.GetType() );

      // here we do find out which objects are holding most of the memory
      MemoryStatistics statOld = dumper.GetMemoryStatistics();
      foreach (var typeInfo in statOld.ManagedHeapStats
                                   .OrderByDescending(x => x.Value.Count))
      {
            Console.WriteLine("Type {0} has {1} instances of total size {2:N0} bytes", 
                           typeInfo.Key, 
                           typeInfo.Value.Count,
                           typeInfo.Value.TotalSize);
      }

      // then check with the info from above who is holding the most interesting new objects. 
      Console.WriteLine("New Strings:"); // just an example perhaps you should have a look at the images.
      foreach (var newStr in newObjects[typeof(string)] )
      {
          Console.WriteLine("Str: {0}", newStr);
      }
   }
}
于 2012-06-24T07:40:59.707 回答
0

在 Windows 上运行的 32 位应用程序(即使操作系统是 64 位)具有 4 Gb 地址空间,但这被分为 2 Gb 应用程序/2 Gb 系统(这可以通过不同的启动开关更改为 3/1)。

您使用的总内存很可能实际上是 2Gb 而不是 1.2Gb,您如何确定这个 1.2Gb 的数字,您是否使用进程资源管理器工具查看了应用程序?

如果您将应用程序更改为 ANYCPU 或 64 位,您应该会发现此限制在 64 位操作系统上消失(很好地移动到更大的值)。

于 2012-06-08T13:18:32.257 回答