我注意到一个内存泄漏问题,在一个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,进程会更快地泄漏内存。
有人能理解为什么会发生这种情况,也许如何解决它(或至少绕过它)吗?
以下是示例代码:
在以下示例中,我有两个服务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();
}
}
catch { }
真的吗?如果你这样做,至少应该注释一下为什么这样做。 - Steve Wellensprivate static void dowork()
中注释掉provider.DoWork();
,即只打开和关闭通道,会发生什么? - Codor