内存泄漏 - WCF 异常
我的 ASP.NET MVC3 应用程序使用 Ninject 通过包装器实例化服务实例。控制器的构造函数有一个 IMyService 参数,操作方法调用 myService.SomeRoutine()。使用 wsHttpBinding 通过 SSL 访问服务 (WCF)。
我有一个搜索例程,它可以返回如此多的结果,以至于超出了我在 WCF 中配置的最大值(对象图中可以序列化或反序列化的最大项目数)。发生这种情况时,服务和客户端的应用程序池都会显着增长,并且在请求结束后仍会保持臃肿状态。
我知道我可以限制结果数量或使用 DTO 来减少传输的数据量。也就是说,我想修复内存泄漏的问题。
使用 CLR Profiler,我看到堆的大部分是由以下项使用:
- System.RunTime.IOThreadTimer.TimerManager
- System.RunTime.IOThreadTimer.TimerGroup
- System.RunTime.IOThreadTimer.TimerQueue
- System.ServiceModel.Security.SecuritySessionServerSettings
- System.ServiceModel.Channels.SecurityChannelListener
- System.ServiceModel.Channels.HttpsChannelListener
- System.ServiceModel.Channels.TextMessageEncoderFactory
- System.ServiceModel.Channels.TextMessageEncoderFactory.TextMessageEncoder
- System.Runtime.SynchronizedPool
- System.Runtime.SynchronizedPool.Entry[]
- ...TextMessageEncoderFactory.TextMessageEncoder .TextBufferedMessageWriter
- System.Runtime.SynchronizedPool.GlobalPool
- System.ServiceModel.Channels.BufferManagerOutputStream
- System.Byte[][]
- System.Byte[] (92%)
另外,如果我修改搜索例程以返回一个空列表(而 NHibernate 的东西仍然在后台进行 - 通过日志记录验证),应用程序池大小保持不变。如果搜索例程无异常地返回重要结果,则应用程序池大小保持不变。我相信当对象列表被序列化并导致异常时就会发生泄漏。
我升级到最新的 Ninject,并使用 log4net 来验证服务客户端是否已关闭或中止,具体取决于其状态(并且该状态从未出现故障)。我发现唯一有趣的是服务包装器正在最终确定并且没有明确处置。
我很难对此进行故障排除,以找出为什么我的应用程序池在这种情况下没有释放内存。我还应该看什么?
更新:这是绑定...
<wsHttpBinding>
<binding name="wsMyBinding" closeTimeout="00:01:00" openTimeout="00:01:00"
receiveTimeout="00:02:00" sendTimeout="00:02:00" bypassProxyOnLocal="false"
transactionFlow="false" hostNameComparisonMode="StrongWildcard"
maxBufferPoolSize="999999" maxReceivedMessageSize="99999999"
messageEncoding="Text" textEncoding="utf-8" useDefaultWebProxy="false"
allowCookies="false">
<readerQuotas maxDepth="90" maxStringContentLength="99999"
maxArrayLength="99999999" maxBytesPerRead="99999"
maxNameTableCharCount="16384" />
<reliableSession enabled="false" />
<security mode="TransportWithMessageCredential">
<message clientCredentialType="UserName" />
</security>
</binding>
</wsHttpBinding>
更新#2:这是 Ninject 绑定,但更奇怪的是错误消息。我的包装器没有正确设置 MaxItemsInObjectGraph,因此它使用默认值。一旦我设置了这个,泄漏就消失了。当服务将序列化数据发送到客户端并且客户端因为超过 MaxItemsInObjectGraph 而拒绝它时,客户端和服务似乎将序列化/反序列化数据保留在内存中。
Ninject 绑定:
Bind<IMyService>().ToMethod(x =>
new ServiceWrapper<IMyService>("MyServiceEndpoint")
.Channel).InRequestScope();
错误消息:
InnerException 消息是“可处理的最大项目数” 对象图中序列化或反序列化为“65536”
这实际上并不能修复内存泄漏,因此我仍然很好奇导致它的原因(如果有人有任何想法)。
My ASP.NET MVC3 application uses Ninject to instantiate service instances through a wrapper. The controller's constructor has an IMyService parameter and the action methods call myService.SomeRoutine(). The service (WCF) is accessed over SSL with a wsHttpBinding.
I have a search routine that can return so many results that it exceeds the maximum I have configured in WCF (Maximum number of items that can be serialized or deserialized in an object graph). When this happens, the application pools for both the service and the client grow noticeably and remain bloated well past the end of the request.
I know that I can restrict the number of results or use DTOs to reduce the amount of data being transmitted. That said, I want to fix what appears to be a memory leak.
Using CLR Profiler, I see that the bulk of the heap is used by the following:
- System.RunTime.IOThreadTimer.TimerManager
- System.RunTime.IOThreadTimer.TimerGroup
- System.RunTime.IOThreadTimer.TimerQueue
- System.ServiceModel.Security.SecuritySessionServerSettings
- System.ServiceModel.Channels.SecurityChannelListener
- System.ServiceModel.Channels.HttpsChannelListener
- System.ServiceModel.Channels.TextMessageEncoderFactory
- System.ServiceModel.Channels.TextMessageEncoderFactory.TextMessageEncoder
- System.Runtime.SynchronizedPool
- System.Runtime.SynchronizedPool.Entry[]
- ...TextMessageEncoderFactory.TextMessageEncoder.TextBufferedMessageWriter
- System.Runtime.SynchronizedPool.GlobalPool
- System.ServiceModel.Channels.BufferManagerOutputStream
- System.Byte[][]
- System.Byte[] (92%)
In addition, if I modify the search routine to return an empty list (while the NHibernate stuff still goes on in the background - verified via logging), the application pool sizes remain unchanged. If the search routine returns significant results without an exception, the application pool sizes remain unchanged. I believe the leak occurs when the list of objects is serialized and results in an exception.
I upgraded to the newest Ninject and I used log4net to verify that the service client was closed or aborted depending on its state (and the state was never faulted). The only thing I found interesting was that the service wrapper was being finalized and not explicitly disposed.
I'm having difficulty troubleshooting this to find out why my application pools aren't releasing memory in this scenario. What else should I be looking at?
UPDATE: Here's the binding...
<wsHttpBinding>
<binding name="wsMyBinding" closeTimeout="00:01:00" openTimeout="00:01:00"
receiveTimeout="00:02:00" sendTimeout="00:02:00" bypassProxyOnLocal="false"
transactionFlow="false" hostNameComparisonMode="StrongWildcard"
maxBufferPoolSize="999999" maxReceivedMessageSize="99999999"
messageEncoding="Text" textEncoding="utf-8" useDefaultWebProxy="false"
allowCookies="false">
<readerQuotas maxDepth="90" maxStringContentLength="99999"
maxArrayLength="99999999" maxBytesPerRead="99999"
maxNameTableCharCount="16384" />
<reliableSession enabled="false" />
<security mode="TransportWithMessageCredential">
<message clientCredentialType="UserName" />
</security>
</binding>
</wsHttpBinding>
UPDATE #2: Here is the Ninject binding but more curious is the error message. My wrapper wasn't setting MaxItemsInObjectGraph properly so it used the default. Once I set this, the leak went away. Seems that the client and service keep the serialized/deserialized data in memory when the service sends the serialized data to the client and the client rejects it because it exceeds MaxItemsInObjectGraph.
Ninject Binding:
Bind<IMyService>().ToMethod(x =>
new ServiceWrapper<IMyService>("MyServiceEndpoint")
.Channel).InRequestScope();
Error Message:
The InnerException message was 'Maximum number of items that can be
serialized or deserialized in an object graph is '65536'
This doesn't actually fix the memory leak so I am still curious as to what have been causing it if anyone has any ideas.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
您如何处理代理客户端的创建和处置?
我发现 WCF 相关内存泄漏的最常见原因是 WCF 代理客户端处理不当。
我建议至少使用像这样的
using
块包装您的客户端:这确保客户端正确关闭和处置,释放内存。
虽然这种方法有点争议,但它应该消除客户端创建时泄漏内存的可能性。
有关此主题的更多信息,请查看此处。
How are you handling your proxy client creation and disposal?
I've found the most common cause of WCF-related memory leaks is mishandling WCF proxy clients.
I suggest at the very least wrapping your clients with a
using
block kinda like this:This ensures that the client is properly closed and disposed of, freeing memory.
This method is a bit controversial though, but it should remove the possibility of leaking memory from client creation.
Take a look here for more on this topic.