我有一个 WCF 客户端应用程序,它发出一个具有非常大响应 (1GB) 的服务调用。我发现进行此服务调用会使用大量内存(500MB),即使我的代码不再引用响应对象,这些内存似乎也永远不会被回收。
我使用内存分析器查看了大部分内存使用情况是由 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() 似乎回收了剩余的 500MB 中的大约 50MB。
尽可能多地回收此一次性服务调用所使用的内存的最佳方法是什么?我即将在一个专用进程中进行服务调用,此时我可以杀死以回收内存。