【问题标题】:Memory Leak - WCF Exception内存泄漏 - WCF 异常
【发布时间】:2012-02-23 17:30:52
【问题描述】:

我的 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'

这实际上并不能解决内存泄漏问题,所以如果有人有任何想法,我仍然很好奇是什么原因造成的。

【问题讨论】:

  • 包装器使用什么绑定?
  • @Remo:我在上面添加了绑定 - 谢谢!
  • 对不起,我不够清楚。我的意思是用于创建包装器的 Ninject Binding。尤其是范围很有趣。
  • 如果您使用的是 Ninject 和 Ninject.MVC2 版本 >= 2.2,则包装器应该在 MVC 请求的末尾进行处理

标签: wcf asp.net-mvc-3 memory-leaks ninject


【解决方案1】:

您如何处理代理客户端的创建和处置?

我发现 WCF 相关内存泄漏的最常见原因是 WCF 代理客户端处理不当。

我建议至少用类似这样的using 块包裹您的客户:

using (var client = new WhateverProxyClient())
{
  // your code goes here
}

这确保客户端被正确关闭和处理,释放内存。

虽然这种方法有点争议,但它应该消除客户端创建时泄漏内存的可能性。

查看here 了解有关此主题的更多信息。

【讨论】:

  • 感谢您的反馈。服务包装器具有 dispose 和 finalize 两者都确保客户端在设置为 null 之前已关闭/中止(使用类似于该文章的代码)。我想我将创建一个测试工具来尝试这种情况的变体,以尝试隔离泄漏。现在变数太多了。
  • -1:既然你知道那篇文章,你为什么建议任何人使用using 块?
猜你喜欢
  • 2012-07-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-02-18
  • 1970-01-01
  • 2014-12-15
相关资源
最近更新 更多