从另一个WCF服务中调用WCF服务时发生WCF内存泄漏
我注意到了WCF应用程序中的内存泄漏问题,并设法将其复制到一个简单的程序中。 从另一个WCF服务中调用WCF服务时会发生此问题。
在下面的例子中,我有两个服务A
和B
当我在服务A
上调用DoWork
方法时,它又调用服务B
的DoWork
方法。
在下面的例子中,我每次创建一个新的ChannelFactory
,使用它打开一个通道,调用DoWork
,然后在最后处理通道和工厂。 这样,该过程开始泄漏内存。
如果我设置了其中一个或两个调用,以便每次重复使用相同的ChannelFactory
(注释并取消注释示例中的标记行),则泄漏将停止。
如果我每次调用服务A
都一直创建一个新的ChannelFactory
,但是会清空ServiceA
的DoWork方法(因此它不调用ServiceB
),则不会发生泄漏。
我正在运行针对.NET 3.5的程序。 奇怪的是,如果我切换到.NET 4,4.5或4.5.1,该进程会更快地泄漏内存。
任何人都可以理解为什么会发生这种情况,也许如何解决它(或者至少可以解决它)?
示例代码如下所示:
using System;
using System.ServiceModel;
namespace memoryleak
{
internal class Program
{
private static void Main()
{
using (var hostA = new ServiceHost(new ServiceA(), new Uri("net.pipe://localhost")))
using (var hostB = new ServiceHost(new ServiceB(), new Uri("net.pipe://localhost")))
{
hostA.AddServiceEndpoint(typeof (ContractA), new NetNamedPipeBinding(), "test_service_a");
hostA.Open();
hostB.AddServiceEndpoint(typeof (ContractB), new NetNamedPipeBinding(), "test_service_b");
hostB.Open();
while(true)dowork();
}
}
//CALLING SERVICE A
//uncomment the following line to reuse the same ChannelFactory each time
//private static readonly ChannelFactory<ContractA> pipeFactory=new ChannelFactory<ContractA>(new NetNamedPipeBinding(),new EndpointAddress("net.pipe://localhost/test_service_a"));
private static void dowork()
{
//comment the following line to reuse the same ChannelFactory each time
var pipeFactory = new ChannelFactory<ContractA>(new NetNamedPipeBinding(), new EndpointAddress("net.pipe://localhost/test_service_a"));
ContractA provider = null;
try
{
provider = pipeFactory.CreateChannel();
provider.DoWork();
}
catch
{
}
finally
{
CloseChannel(provider);
//comment the following line to reuse the same ChannelFactory each time
try { pipeFactory.Close(); }catch{pipeFactory.Abort();}
}
}
private static void CloseChannel(ContractA provider)
{
try
{
if (provider == null)
return;
try
{
((IClientChannel) provider).Close();
}
catch
{
((IClientChannel) provider).Abort();
}
((IDisposable) provider).Dispose();
}
catch (Exception ex)
{
throw new Exception("Error while closing channel", ex);
}
}
}
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Multiple)]
public class ServiceA : ContractA
{
//CALLING SERVICE B
//uncomment the following line to reuse the same ChannelFactory each time
//private readonly ChannelFactory<ContractB> pipeFactory=new ChannelFactory<ContractB>(new NetNamedPipeBinding(),new EndpointAddress("net.pipe://localhost/test_service_b"));
public void DoWork()
{
//comment the following line to reuse the same ChannelFactory each time
var pipeFactory=new ChannelFactory<ContractB>(new NetNamedPipeBinding(),new EndpointAddress("net.pipe://localhost/test_service_b"));
ContractB provider = null;
try
{
provider = pipeFactory.CreateChannel();
provider.DoWork();
}
catch
{
}
finally
{
CloseChannel(provider);
//comment the following line to reuse the same ChannelFactory each time
try { pipeFactory.Close(); } catch { pipeFactory.Abort(); }
}
}
private void CloseChannel(ContractB provider)
{
try
{
if (provider == null)
return;
try
{
((IClientChannel) provider).Close();
}
catch
{
((IClientChannel) provider).Abort();
}
((IDisposable) provider).Dispose();
}
catch (Exception ex)
{
throw new Exception("Error while closing channel", ex);
}
}
}
[ServiceContract]
public interface ContractA
{
[OperationContract]
void DoWork();
}
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Multiple)]
public class ServiceB : ContractB
{
public void DoWork()
{
}
}
[ServiceContract]
public interface ContractB
{
[OperationContract]
void DoWork();
}
}
可能发生的情况是,您创建对象的速度比默认工作站垃圾收集器可以摆脱它们的速度快。 .net 3.5 GC的默认延迟模式是交互式的,这意味着如果为了保持UI响应而收集时间过长,它会放弃。 GC在.net 4和4.5中的工作方式不同,这可能是您看到不同增长率的原因。
尝试在App.config中启用服务器垃圾收集模式,并查看行为是否改变。 这应该允许GC工作,直到完成。
<configuration>
<runtime>
<gcServer enabled="true"/>
</runtime>
</configuration>
我假设你正在使用多核系统,否则这将没有效果。
链接地址: http://www.djcxy.com/p/54939.html上一篇: WCF memory leak when calling WCF service from within another WCF service