我注意到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),"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(); } }