WCF服务内存泄漏

7

我有一个非常小的WCF服务,托管在控制台应用程序中。

[ServiceContract]
public interface IService1
{
    [OperationContract]
    void DoService();
}

[ServiceBehavior(InstanceContextMode=InstanceContextMode.PerCall)]
public class Service1 : IService1
{
    public void DoService()
    {

    }
}

它被称为

using (ServiceReference1.Service1Client client = new ServiceReference1.Service1Client())
{
    client.DoService(new DoServiceRequest());
    client.Close();
} 

请记住,服务是基于basicHttpBindings发布的。
问题:
现在,当我在循环中执行上述客户端代码1000次时,我发现“All Heap bytes”和“Private Bytes”性能计数器之间存在很大差异(我使用了.net内存分析器)。经过调查,我发现一些对象没有被正确处理。以下是这些对象的列表(找到了1000个未处理的实例-->等同于客户端调用)。
(所有这些对象的命名空间均为System.ServiceModel.Channels)
HttpOutput.ListenerResponseHttpOutput.ListenerResponseOutputStream
BodyWriterMessage
BufferedMessage
HttpRequestContext.ListenerHttpContext.ListenerContextHttpInput.ListenerContextInputStream
HttpRequestContext.ListenerHttpContext 

问题 为什么我们有很多未处理的对象,如何控制它们。

请帮忙。


1
在我看来,这似乎是一个系统库泄漏。客户端(即用户编写的服务)代码不会触及那些缓冲区和流,而且似乎WCF没有对它们进行处理。 - Igor Zevaka
马布沙尔:你在这方面有什么运气吗?我似乎遇到了类似的问题。 - bugfixr
@bugfixr 抱歉兄弟,我今天才看到你的留言,我不记得是否成功解决了那些问题,但我记得我从框架 3.5 转移到了框架 4.0,这在某种程度上或完全上帮助了我。对于迟到的回复感到抱歉。 - Mubashar
3个回答

6
您正在每次调用时请求一个新实例(InstanceContextMode=InstanceContextMode.PerCall)。如果在1000次调用中没有发生GC,那么服务实例将不会被回收。WCF要求您实现IDisposable接口。
来自MSDN:了解为开发WCF应用程序提供强大的实例管理技术
短语“Per-Call Services” 表示每次调用创建的服务实例。当服务类型配置为per-call激活时,一个CLR对象即服务实例只存在于客户端调用期间。每个客户端请求都获得一个新的专用服务实例。图2说明了这个单一调用激活过程是如何工作的。
图片链接:Figure 2 Per-Call Instantiation
(来源: microsoft.com)
以下是服务调用的步骤:
1. 客户端调用代理并将调用转发给服务。 2. Windows Communication Foundation 创建服务实例并调用其方法。 3. 方法调用返回后,如果该对象实现IDisposable,则Windows Communication Foundation调用IDisposable.Dispose方法。

3
我之前看过这篇文章,确实如此,如果存在Dispose方法,则会自动调用它。但仅当你自己打开了某些资源并需要进行清理时才会发生,此时需要自己清理。但在我的情况下,我没有需要清理的资源。不过我已经尝试过这个方法,但结果相同。另外,我想告诉你,GC已经清理了堆内存,但是由于那些对象未被处理,所以本机内存没有被清理。 - Mubashar

1

你有没有偶然启用性能计数器?像下面这样?

<system.serviceModel>
  <diagnostics performanceCounters="All" />
  ..
</system.serviceModel>

在链接http://msdn.microsoft.com/en-us/library/ms735098.aspx的“增加性能计数器的内存大小”段落中提到,启用WCF性能计数器时可能会出现“流氓”私有字节计数。将其更改为ServiceOnly或完全禁用(Off)可能会解决问题。

1

我在2010年找到了解决方案,但是我忘记发布它了。我确实失去了确切的记录,但我记得这是一个.Net库的错误,已向微软报告并得到了确认。我没有它的链接,但我一旦能找到它就会发布。无论如何,微软已经在.net 4.0中修复了这个问题,这也是我遵循的确切解决方案,我知道对于你们中的一些人来说,由于服务器环境的变化有时不在你们的掌握之中,这可能是不可能的。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接