1

我有一个 .NET 应用程序,仅当我在 Windows 7 模式下以 x86 运行它时内存不足,但有以下异常

8/4/2013 11:36:52 AM: Main application context(1) CriticalError:    Exception in Application context Run: Main application context : Parameter is not valid.   at System.Drawing.Image.get_Width()
   at System.Drawing.Image.get_Size()
   at DevExpress.XtraBars.BarItem.IsSameSize(Image old, Image newImage)
   at DevExpress.XtraBars.BarItem.set_Glyph(Image value)
   at NordicIT.Mark5.Module.DM.Editor.frmEditorRibbon..ctor()
   at NordicIT.Mark5.Module.DM.Editor.frmEditorRibbon..ctor(IEditFormForBOOptions editFormForBOOptions)
   at NordicIT.Mark5.Module.DM.Actions.TDMActions.<>c__DisplayClass19.<_DocumentTransmitProcess>b__17()
   at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Int32 numArgs)

内存消耗大约 400 mb,GDI 对象消耗大约 1500(我已经在注册表中增加了这些限制,所以到 10000 左右应该没有问题)。

当我在 x86 中的 Windows Server 2008 R2 中运行相同的应用程序时,我没有问题(它应该具有与 Windows 7 相同的内核),在 x86 中的 Windows xp 中也没有问题。

即使我使用高达 2 GB 的内存,我在 x64 模式下也不会出现异常。

请帮助我了解我正在达到的内存限制。

4

1 回答 1

8

GDI+ 异常相当糟糕,这是因为它早在 .NET 出现之前就已经开发出来并且只有一些错误代码。在这种情况下,实际上很可能是内存问题。“参数无效”是GDI+对无法加载图像的原因。这可能是因为图像文件包含垃圾,这反过来又会使其尝试分配过多的内存。在大量情况下选择不当。

无论您的机器有多少 RAM,32 位进程都有 2 GB 的虚拟内存。地址空间需要由代码和数据共享。其中的大块将被 CLR、jitter、框架程序集、程序集、程序的 jitted 代码以及 .NET 程序使用的大约 10 个不同的堆(包括 GC 堆)占用。这些块的分配往往分散在地址空间中。当您分配内存时,您将从这些现有块之间的可用孔中获取另一个块。

位图的一个大问题是它们可能非常。它们需要安装在可用的孔内。随着程序分配和释放内存,这些漏洞会随着时间的推移而变小。一个称为“地址空间碎片”的问题。当您的程序第一次启动时,您通常会发现一个大约 650 兆字节的漏洞。但是当你的程序运行了一段时间后,它会迅速下降。长期运行的程序的危险区域大约是 90 兆字节,不管是给予还是索取。

当没有足够大的孔可以容纳位图时,您的程序会出现此异常。这将在您的程序消耗所有可用虚拟内存之前很久发生。您可以进行许多小分配,但不能进行大分配。

这个问题没有简单的解决方法。除了一个。将 EXE 项目上的 Target platform 设置更改为 AnyCPU,关闭 VS2012 及更高版本的“Prefer 32-bit”。在 64 位操作系统上,程序具有更大的 VM 地址空间,可能达到 TB。你根本无法用完足够大的洞。如果您被 32 位进程卡住,一个困难的解决方法是使用另一个进程来加载位图。这又为您购买了 2 GB 的干净地址空间。不经常实用。

您可以使用 SysInternals 的 VMMap 实用程序来深入了解程序的 VM 使用情况。您可能会发现一个 DLL 加载到一个非常尴尬的地址,将一个大洞切成两个小洞。但是不要抱太大希望,你往往会首先完全淹没在数据中。

于 2013-08-04T14:19:47.993 回答