2010-04-22 39 views
5

这种情况是,我正在对作为字符串返回XML文档的远程服务器进行WCF调用。如何最大化大对象堆中最大的连续内存块

大部分时间这个返回值是几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) 

我读过周围,这是因为大对象堆是刚开过于分散,所以即使是调用一个快速检查,以StringBuilder.EnsureCapacity前面的正义事业OutOfMemoryException会在更早的时候抛出(并且因为我在猜测需要什么,它可能并不需要那么多,所以我的检查导致的问题比解决问题的更多)。一些opinions是,我没有太多的事情可以做。

一些我问自己的问题:

  • 使用较少的内存 - 你检查是否有泄漏?是的。内存使用量上升和下降,但没有保证这种情况发生的根本性增长。有些时候它失败了,它在此之前就已经成功了。
  • 传输少量不是一种选择,这是一个第三方Web服务在这我管不着(或至少它需要很长的时间来解决,在此期间,我仍然有一个问题)
  • 你可以对蕙兰做些什么,使它不太可能失败? ...现在这是最富有成果的课程。这是一个32位程序(它必须出于各种政治,技术和无聊的原因),但通常有数百兆的免费(我们已经看到失败的最大数量的倍数)。
  • 我们可以监控LOH吗?使用perfmon我可以跟踪堆的大小,但我不认为有办法监视最大的可用连续内存块。

问题是:任何建议或建议的事情尝试?

回答

5

你可以查看你的结合,看看您是否符合要求将其从“缓冲”的它的默认值改变TransferMode财产,“串流播放”或“StreamedResponse”。

此外,查看maxBufferPoolSizemaxBufferSize的值。使用内部缓冲区的大小可以帮助提高内存利用率,尤其是处理大量消息时。

maxReceivedMessageSize也可能已经设置,如果您接收大消息,但我也会检查该值。

我见过上面的一个值,如果你超过了阈值,就会失败,出现一个模糊的,与内存相关的消息。原来的异常实际上隐藏在我的应用程序中的消息中。启用WCF跟踪帮助诊断问题并查看真正的错误 - 我需要增加上述一个或多个绑定属性的值。

我没有感受到您在帖子中使用的绑定的感觉,但我相信这些设置在主要的设置中很常见。例如,查看basicHttpBinding上的MSDN文档。

如果真的是LOH碎片化,那么一旦调整工作已经耗尽,没有什么可以做的。应用程序的滚动回收可能需要缓解它(我讨厌推荐),但如果你已经用尽了其他的努力,你可能会留下它。

+0

更改绑定是一个好主意 - 我会试试看。 滚动回收是我们的最后手段... – Unsliced 2010-04-22 14:13:35

+0

我们很幸运,通过代码改进(尽管我们拥有两个端点)或绑定更改来缓解大文档处理中的任何问题,至少让我们通过到定期维护回收(由于修补,功能发布等)。 @Steven的使用windbg进行堆分析的想法也可以带来好处。试试http://blogs.msdn.com/tess/,你会发现Tess Ferrandez有关如何从这里开始的好消息。优秀的实验室! 祝你好运! – 2010-04-22 14:24:00

1

我认为你的问题也许是大会泄漏因使用XmlSerializer的,而不是使用两个构造之一,因为在这个MSDN article表示:

为了提高性能,在XML 序列化基础 动态生成汇编到 序列化和反序列化指定的 类型。基础架构发现并且 重用了这些程序集。这种行为 使用以下 构造函数时只发生:

XmlSerializer.XmlSerializer(类型)

XmlSerializer.XmlSerializer(类型, 字符串)

如果您使用任何其他 构造的,多生成 相同组件的版本,并且从未卸载 ,这导致内存泄漏和性能不佳。

不错,呵呵。答案是缓存你的XmlSerializer(假设你甚至创建它)。

要真正搞清楚,你需要做Tess告诉你要做的事情。她是一个怪胎天才。

1

如果可能的话,我会选择一种基于流的方法,并结合使用只向前的Xml解析器,这应该也会给你更好的性能。

如果你不一定要使用WCF,你可以编写你自己的HttpRequest,然后将响应传递给XmlDeserializer,然后解析类似的响应。它可能会让您更好地控制并洞察问题实际发生的位置。你也可以尝试一个模拟服务,返回你正在寻找的非常大的文档。 我们也有很多头痛的LOH碎片,所以我真的感到你的痛苦。

构建缓冲区时,我注意到了一个问题.NET每次填充缓冲区时容量翻倍,这会导致内存碎片,因为对于大小为10mb的文档,内存需要在很多步骤中分配。如果您事先知道所需的缓冲区大小,则一次分配它会更有效。因此,如果您知道传入文档的大小,您可以创建一个完全相同大小的StringBuilder。

2

我无法解决任何WCF特定问题,但是如果您需要最大化32位进程的LOH空间,则应该使应用程序large address aware在64位上运行。在64位Windows上运行时,一个支持大地址的32位进程将能够处理整个4 GB地址空间。这将使您在进程通常使用的地址空间之上有相当大的内存空间。