2012-11-08 14 views
3

我有一個WCF客戶端應用程序,它使用一個非常大的響應(1GB)進行單個服務調用。我發現使這個服務調用使用了很多內存(500MB),即使響應對象不再被我的代碼引用,它似乎永遠不會被回收。如何清除我曾用過的一次WCF HTTP客戶端的PooledBufferManager?

我已經使用內存分析器來查看PooledBufferManager實例創建的字節數組中的大部分內存使用情況。

我正在使用的代理/客戶端已由Visual Studio自動生成,因此它是從System.ServiceModel.ClientBase派生的類< TChannel>。

我使用一個自定義的具有以下配置綁定:

<customBinding> 
    <binding name="foo" 
      closeTimeout="00:01:00" 
      openTimeout="00:01:00" 
      receiveTimeout="00:01:00" 
      sendTimeout="00:01:00"> 
     <transactionFlow/> 
     <reliableSession ordered="true" inactivityTimeout="00:02:00"/> 
     <security authenticationMode="SecureConversation" messageSecurityVersion="WSSecurity11WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10"> 
     <secureConversationBootstrap messageSecurityVersion="WSSecurity11WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10"> 
      <localClientSettings maxClockSkew="23:59:00"/> 
     </secureConversationBootstrap> 
     <localClientSettings maxClockSkew="23:59:00"/> 
     </security> 
     <mtomMessageEncoding> 
     <readerQuotas maxDepth="2147483647" maxStringContentLength="2147483647" maxArrayLength="2147483647" maxBytesPerRead="2147483647" maxNameTableCharCount="2147483647"/> 
     </mtomMessageEncoding> 
     <httpTransport maxBufferPoolSize="2147483647" maxBufferSize="2147483647" maxReceivedMessageSize="2147483647"/> 
    </binding> 
    </customBinding> 

周圍的人閱讀談論了幾個解決方案,以這樣的:

  • 切換到流媒體的反應模式,而不是緩衝,但我相信這是針對TCP WCF連接的,而不是像我的那樣的HTTP。
  • 將maxBufferPoolSize設置爲零以禁用緩衝池。在httpTransport元素中設置它對我來說似乎沒有任何影響。
  • 在適當的BufferManager/PooledBufferManager上調用Clear()。我無法從ClientBase派生實例的上下文中找到要調用此對象的對象。我確實設法使用調試器找到合適的PooledBufferManager實例,並深入挖掘私有innerChannelFactory字段中的許多級別,但這對於從代碼與其進行交互沒有用處。
  • 手動調用GC.Collect()似乎回收大約50MB的優秀500MB。

回收儘可能多的這種一次性服務呼叫使用的內存的最佳方法是什麼?我正在接受一個專門過程中的服務呼叫,我可以在這一點上殺死回收內存。

回答

2
  • 切換到流響應模式,而不是緩衝,但我相信這是對TCP連接WCF,不支持HTTP像我這樣。

即使有HTTP,你其實可以切換到和我一樣的https流模式,但HTTP does work只是as well

只需將transferMode="Streamed"屬性添加到您的httpTransport元素即可。由於您擔心客戶,您需要在客戶的app.config中執行此操作。 (你也可以在服務器的web.config中獨立完成它,如果你也想把服務器改爲streamed模式,但不需要改變客戶端和服務器,傳輸模式不會改變線上的字節)

  • 將maxBufferPoolSize設置爲零以禁用緩衝池。在httpTransport元素中設置它對我來說似乎沒有任何影響。

這正是this article索賠應該工作:

如果maxBufferPoolSize = 0,則GCBufferManager被創建,否則你得到一個PooledBufferManager。前者是微不足道的,事實上並不真正進行任何管理,只是爲任何請求分配一個新的緩衝區,並讓垃圾回收器負責處理它。

即手動GC.Collect()其實可以做的伎倆在這種情況下。

  • 調用適當的BufferManager/PooledBufferManager清除()。我無法從我擁有的ClientBase派生實例的上下文中找到要調用它的對象。

我無法訪問那個BufferManager實例,當我嘗試這個時候。

  • 手動調用GC.Collect的()似乎回收約優秀500MB的50MB。

不會爲彙集緩衝區管理工作,因爲它永遠不會釋放緩衝區一旦創建,除非你叫Clear(),你不能,缺乏一個指向實例。