现在的情况是我正在调用远程服务器的WCF,它返回一个XML文档作为字符串。
大多数情况下,这个返回值只有几K,有时是几十K,非常偶尔会达到几百K,但很少会超过几兆字节(首要问题是我无法知道实际大小)。
正是这些罕见的情况导致了问题。我得到了一个堆栈跟踪,它开始于:
System.OutOfMemoryException: Exception of type 'System.OutOfMemoryException' was thrown.
at System.Xml.BufferBuilder.AddBuffer()
at System.Xml.BufferBuilder.AppendHelper(Char* pSource, Int32 count)
at System.Xml.BufferBuilder.Append(Char[] value, Int32 start, Int32 count)
at System.Xml.XmlTextReaderImpl.ParseText()
at System.Xml.XmlTextReaderImpl.ParseElementContent()
at System.Xml.XmlTextReaderImpl.Read()
at System.Xml.XmlTextReader.Read()
at System.Xml.XmlReader.ReadElementString()
at Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationReaderMDRQuery.Read2_getMarketDataResponse()
at Microsoft.Xml.Serialization.GeneratedAssembly.ArrayOfObjectSerializer2.Deserialize(XmlSerializationReader reader)
at System.Xml.Serialization.XmlSerializer.Deserialize(XmlReader xmlReader, String encodingStyle, XmlDeserializationEvents events)
at System.Xml.Serialization.XmlSerializer.Deserialize(XmlReader xmlReader, String encodingStyle)
at System.Web.Services.Protocols.SoapHttpClientProtocol.ReadResponse(SoapClientMessage message, WebResponse response, Stream responseStream, Boolean asyncCall)
at System.Web.Services.Protocols.SoapHttpClientProtocol.Invoke(String methodName, Object[] parameters)
我看了一些资料,发现问题是由于大对象堆(Large Object Heap)过于碎片化,因此即使在调用之前快速检查StringBuilder.EnsureCapacity也只会导致OutOfMemoryException更早地抛出(而且因为我猜测所需的容量,可能实际上并不需要那么多,所以我的检查反而会带来更多问题)。一些观点认为,这个问题并没有太多解决办法。
我问自己的一些问题:
- 使用更少的内存——你检查过泄漏吗? 是的。内存使用量上下波动,但没有基本增长可以保证发生这种情况。有时它失败了,而在那个阶段之前它是成功的。 - 传输更小的数据量 不可行,这是一个第三方网络服务,我无法控制(或者至少需要很长时间才能解决,在此期间我仍然有问题)。 - 你能做些什么来减少LOH失败的可能性吗? ……现在这是最有成效的方法。这是一个32位进程(由于各种政治、技术和乏味的原因),但通常有数百兆的空闲内存(是最大失败量的多倍)。 - 我们能监视LOH吗? 使用perfmon可以跟踪堆的大小,但我不认为有一种方法可以监视可用的最大连续内存块。
问题是:有没有什么建议或尝试的事情?