2

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

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

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

4 回答 4

2

这是我的测试 - 请注意lambda 中的显式proxy设置- 没有它的生命,因此可能会泄漏:nullWeakReference

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);
    }
}
于 2008-11-07T05:05:26.440 回答
1

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

于 2008-11-07T04:39:09.660 回答
0

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

于 2011-10-20T18:20:16.847 回答
-1

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

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

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

于 2008-11-07T04:20:11.727 回答