【问题标题】:Will this WCF client side code cause a memory leak?这个 WCF 客户端代码会导致内存泄漏吗?
【发布时间】:2008-11-07 03:52:18
【问题描述】:

.Net 中内存泄漏的常见原因之一是永远不会从源对象中删除的事件处理程序。

此 WCF 代码会导致内存泄漏,还是 lambda 也会超出范围,从而允许代理类和处理程序都被 GCed?

void AMethod()
{
    WCFClient proxy;
    proxy = new WCFClient();
    proxy.RemoteOperationCompleted += (sender, e) => proxy.Close();
    proxy.Open();
    proxy.RemoteOperationAsync();
}

【问题讨论】:

    标签: c# .net wcf lambda


    【解决方案1】:

    这是我的测试 - 请注意 lambda 中设置为 null 的显式 proxy - 没有它,WeakReference 仍然存在,因此很可能发生泄漏:

    public class Proxy
    {
        private bool _isOpen;
    
        public event EventHandler Complete;
    
        public void Close() 
        {
            _isOpen = false;
        }
    
        public void Open() 
        { 
            _isOpen = true; 
        }
    
        public void RemoteOperationAsync()
        {
            if (!_isOpen)
                throw new ApplicationException();
            Thread.Sleep(1000);
            if (Complete != null)
                Complete(this, EventArgs.Empty);
        }
    }
    
    public static class Program
    {
        public static void Main()
        {
            WeakReference wr = null;
    
            {
                var proxy = new Proxy();
                proxy.Complete += (sender, e) =>
                    {
                        proxy.Close();
                        wr = new WeakReference(proxy);
                        proxy = null;
                    };
                proxy.Open();
                proxy.RemoteOperationAsync();
            }
    
            GC.Collect(GC.GetGeneration(wr));
            GC.WaitForPendingFinalizers();
    
            Console.WriteLine("[LAMBDA] Is WeakReference alive? " + wr.IsAlive);
        }
    }
    

    【讨论】:

    • 是不是因为当前的方法作用域还没有展开(所以GC不会清理它们)?将它们放在一个方法中,GC.Collect 并检查 wr 作为 Main 中的一个字段。没有proxy = null,它就没有生命。
    【解决方案2】:

    不要忘记代理没有正确实现 IDisposable。如果发生错误,上面的代码将不会清理连接,并且句柄将一直保留到父进程关闭。

    【讨论】:

      【解决方案3】:

      将捕获定义 lamdba 的上下文,因此将在编译器创建的闭包类中“存活”(您可以使用 Reflector 看到它们) - 所以您的代理也是如此。使用弱事件处理程序或编写注销代码。但在这种情况下,你不能使用 lambda 表达式。

      【讨论】:

        【解决方案4】:

        那个物体会死……它会被清理干净。

        不要忘记 lamda 并没有做任何特别的事情......这是一个编译器技巧(所以假设它是一个正常的 += SomeDelegate)。

        此外,“关闭”方法(我不知道他们为什么不将其设为 IDisposable)会清理其他所有未打开的内容。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2015-01-24
          • 1970-01-01
          • 2012-01-18
          相关资源
          最近更新 更多