2010-04-22 47 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地址空間。這將使您在進程通常使用的地址空間之上有相當大的內存空間。