我们的客户偶尔会在我们的应用程序中发现内存不足异常。由于我们记录了他们的行为,我们可以大致重现他们的行为,但是如果我这样做并使用dotMemory对应用程序进行分析,我就无法重现异常并且使用的内存(大约100 MB托管+ 500MB非托管)远小于限制(2GB,因为它是32位应用程序)。此外,在捕获异常时,使用Process.GetCurrentProcess()请求当前内存使用情况.Workting6464指示500到900 MB之间的内存使用量。我知道这个数字不是很可靠,但它是另一个迹象表明应该有足够的可用内存。
该应用程序的相关属性是它处理时间序列的测量(DateTime和double存储在数组中)。这些对象可能足够大,可以存储在大对象堆(LOH)中。因此,堆碎片确实会发生,但在分析时,不似乎是一个大问题。 LOH的大小小于100MB 包括孔。
是否可能在抛出内存不足异常后调用垃圾收集器(GC)?我认为,在不满意的内存分配请求的情况下,仅当GC无法收集足够的内存时才会抛出异常。但是,与在第0代堆中分配的内存相比,LOH中分配的内存可能有所不同吗?
有谁有想法,我们如何解决这个问题?
我们正在使用VS 2010 SP1和.NET 4.0。 该问题可能与提出的问题here有关, here和here,但我在那里找不到令人满意的答案。
更新:添加了示例堆栈跟踪和堆栈图表
没有独特的地方可以触发内存不足异常,但是由于它被请求,我添加了一个strack跟踪:
Exception of type 'System.OutOfMemoryException' was thrown.
mscorlib
at System.Runtime.Serialization.ObjectIDGenerator.Rehash()
at System.Runtime.Serialization.ObjectIDGenerator.GetId(Object obj, Boolean& firstTime)
at System.Runtime.Serialization.Formatters.Binary.ObjectWriter.InternalGetId(Object obj, Boolean assignUniqueIdToValueType, Type type, Boolean& isNew)
at System.Runtime.Serialization.Formatters.Binary.ObjectWriter.Schedule(Object obj, Boolean assignUniqueIdToValueType, Type type, WriteObjectInfo objectInfo)
at System.Runtime.Serialization.Formatters.Binary.ObjectWriter.WriteMembers(NameInfo memberNameInfo, NameInfo memberTypeNameInfo, Object memberData, WriteObjectInfo objectInfo, NameInfo typeNameInfo, WriteObjectInfo memberObjectInfo)
at System.Runtime.Serialization.Formatters.Binary.ObjectWriter.WriteMemberSetup(WriteObjectInfo objectInfo, NameInfo memberNameInfo, NameInfo typeNameInfo, String memberName, Type memberType, Object memberData, WriteObjectInfo memberObjectInfo)
at System.Runtime.Serialization.Formatters.Binary.ObjectWriter.Write(WriteObjectInfo objectInfo, NameInfo memberNameInfo, NameInfo typeNameInfo, String[] memberNames, Type[] memberTypes, Object[] memberData, WriteObjectInfo[] memberObjectInfos)
at System.Runtime.Serialization.Formatters.Binary.ObjectWriter.Write(WriteObjectInfo objectInfo, NameInfo memberNameInfo, NameInfo typeNameInfo)
at System.Runtime.Serialization.Formatters.Binary.ObjectWriter.Serialize(Object graph, Header[] inHeaders, __BinaryWriter serWriter, Boolean fCheck)
at System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Serialize(Stream serializationStream, Object graph, Header[] headers, Boolean fCheck)
... <methods from our application follow>
dotMemory的下图描绘了使用该工具工作约一小时后的LOH碎片:
答案 0 :(得分:2)
使用工具vmmap我找到了问题的原因:可用于托管堆的实际内存远小于2GB限制。加载了几个用于与MS Office工具交互的共享库(~400 MB)。还有本机代码dll(~300MB),它也分配非托管堆(~300MB)。还有很多其他的东西,最后,托管堆只剩下大约700MB。
由于可用内存比我原先想象的少得多,因此LOH碎片可能比我怀疑的更具影响力:vmmap显示,即使可用内存,该内存区域中最大的空闲块也会比计时器变小保持原样。我认为,这证明了碎片是导致问题的原因。异常的触发器通常是我们有时用于深度复制对象的二进制序列化。它似乎会导致内存使用量达到峰值。
那该怎么办呢?我正在考虑以下选项: