两台PC上的OutOfMemory异常

时间:2013-04-15 17:34:03

标签: .net memory memory-management

鉴于两台PC

  1. Core i5第3代4GB内存(Dell Optiflex 7010)
  2. 酷睿i7第二代16GB内存(三星700G7C)
  3. 更新1 - 有趣的是,将T的属性数量减少两倍没有任何变化,OOM发生的集合中的Ts数量保持不变...

    采取平均低频率,我只是没有他们的手。

    任何人都可以向我解释一下,为什么在第一台PC上运行完全正常的代码在第二台PC上运行失败100%的时候出现OutOfMemoryException?考虑到第二台PC成本高出3倍,这真的很烦人。

    我不能在这里发布整个代码,但它非常简单 - 一个List用T填充,其中T是一个具有5个整数属性的CLR对象。第一台PC处理25M对象没问题(这就是我所看到的,它可能可以处理更多),而第二台PC处理大约。 16.5M记录。我知道单个对象内存限制,但它真正得到的是它如何在两个相当现代的PC之间偏离这么多(50%++)?

3 个答案:

答案 0 :(得分:3)

问题严重不足,但我可以对其进行逆向工程。首先,你可以用尽内存的唯一方法是使用结构列表而不是类。这使得结构大小为4 * 5 = 20个字节。在1650万个元素中,您需要一个用于List<>的内部数组。具有至少20 x 16.5 = 330 MB的连续虚拟内存。下一个分配将要求双倍大小,660兆字节。在32位进程中很难实现。 OOM的风险与该规模非常接近。

问题在于您需要 continguous 分配。换句话说,虚拟内存地址空间中未使用的空洞至少为660兆字节。麻烦的是VM空间需要由代码和数据共享。代码是这里常见的麻烦制造者。一个DLL加载到一台机器而不是另一台机器上。像英特尔的铲刀,供应商或病毒扫描仪。 DLL具有可能非常笨拙的首选加载地址,将可用地址空间分成两个较小的部分。这些部分的总和仍然足够大,但没有留下足够大的空洞来适应660 MB的分配。

这是一个称为“地址空间碎片”的一般问题。它始终是OOM的第一个原因,消耗所有2千兆字节的可用地址空间非常困难。这只能通过进行非常小的分配来实现。

您可以采取一些非常简单的方法来解决此问题:

  • 摆脱该机器上的铲子,使用SysInternals的VMMap实用程序查看是否有效
  • 使用类而不是结构。现在List元素大小只有4个字节而不是20个
  • 使用List<> .Capacity属性。这可以减少在列表增长时多次重新分配内部数组所产生的地址空间碎片。只要你有一个很好的初步猜测。
  • 你有很好的硬件,使用它。将EXE项目上的目标平台设置更改为AnyCPU。 64位进程有大量的地址空间,很难全部消耗。
  • 您可以在EXE上使用/ LARGEADDRESSAWARE选项运行Editbin.exe。现在,您的32位进程在64位操作系统上将具有4 GB的地址空间。

答案 1 :(得分:1)

这可能听起来很奇怪,但很容易排除。使用memory profiler并注意泄漏源。

我能找出低规格硬件的唯一方法是生存,而高失败则是内存碎片。 GC并不擅长这一点。

答案 2 :(得分:0)

将构建平台设置为x64(默认设置为Any Platform)已解决了我的问题。我尝试了一些好的食谱,包括gcAllowVeryLargeObjects和强制x86,但无济于事。