C#活动内存泄漏 [英] C# Events Memory Leak

查看:155
本文介绍了C#活动内存泄漏的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在做这些退订事件发生内存泄漏?我应该写析构函数或实现IDisposable退订的事件吗?

When does these unsubscribed events memory leak occurs? Should I write destructor or implement IDisposable to unsubscribe an event?

推荐答案

让我们说的 A 引用的。此外,说你觉得你有做的并期望它是垃圾回收。

Let's say that A references B. Furthermore, say you think you're done with B and expect it to be garbage collected.

现在,如果 A 可达的[1],不会被垃圾收集,尽管你它完成。这一点,在所有的精华,一个的内存泄漏的[2]

Now, if A is reachable[1], B won't be garbage collected, despite the fact that "you're done with it". This is, in all essence, a memory leak[2]

如果订阅事件中的 A ,然后我们有同样的情况: A B中的参考通过事件处理程序委托。

If B subscribes to an event in A, then we have the same situation: A has a reference to B via the event handler delegate.

所以,当这是个问题吗?只有当引用对象是可到达的,如上所述。在这种情况下,是泄漏时,未使用的实例再:

So, when is this a problem? Only when the referencing object is reachable, as mentioned above. In this case, there can be a leak when a Foo instance isn't used any longer:

class Foo
{
    Bar _bar;

    public Foo(Bar bar)
    {
        _bar = bar;
        _bar.Changed += BarChanged;
    }

    void BarChanged(object sender, EventArgs e) { }
}

为什么有的原因就可以是一个泄漏的是,在实例传入构造的可以有更长的寿命比<强>富使用它的实例。订阅事件处理程序的可以,然后保持在活着。

The reason why there can be a leak is that the Bar instance passed in the constructor can have a longer lifetime than the Foo instance using it. The subscribed event handler can then keep the Foo alive.

在这种情况下,您需要提供一种方法从事件退订不了内存泄漏。这样做的一个方法是通过让实施的IDisposable 。那好处是完成时,它清楚地表明对类消费者,他需要调用的Dispose()。另一种方法是有单独的订阅()取消()的方法,但是,这并不传达类型的期望 - 他们太随意调用并推出时间耦合

In this case you need to provide a way to unsubscribe from the event to not get a memory leak. One way of doing that is by letting Foo implement IDisposable. The upside of that is that it clearly signals to the class consumer that he need to call Dispose() when done. Another way is to have separate Subscribe() and Unsubscribe() methods, but that doesn't convey the type's expectations - they are too optional to call and introduce a temporal coupling.

我的建议是:

class sealed Foo : IDisposable
{
    readonly Bar _bar;
    bool _disposed;

    ...

    public void Dispose()
    {
        if (!_disposed)
        {
            _disposed = true;
            _bar.Changed -= BarChanged;
        }
    }

    ...
}

或者:

class sealed Foo : IDisposable
{
    Bar _bar;

    ...

    public void Dispose()
    {
        if (_bar != null)
        {
            _bar.Changed -= BarChanged;
            _bar = null;
        }
    }

    ...
}

在另一方面,当引用对象的不是可达,有不能是一个泄漏:

On the other hand, when the referencing object isn't reachable, there can't be a leak:

class sealed Foo
{
    Bar _bar;

    public Foo()
    {
        _bar = new Bar();
        _bar.Changed += BarChanged;
    }

    void BarChanged(object sender, EventArgs e) { }
}

在此情况下,任何的实例总是活得比其组成的实例。当不可达,所以将它的会。订阅事件处理程序不能保持在这里存活。这种方法的缺点是,如果酒吧是需要在单元测试场景被嘲笑的依赖,它不能(在任何清洁方式),明确由消费者实例化,但需要注入

In this case any Foo instance will always outlive its composed Bar instance. When a Foo is unreachable, so will its Bar be. The subscribed event handler cannot keep the Foo alive here. The downside of this is that if Bar is a dependency in need of being mocked in unit testing scenarios, it can't (in any clean way) be explicitly instantiated by the consumer, but needs to be injected.

[1] <一个href=\"http://msdn.microsoft.com/en-us/magazine/bb985010.aspx\">http://msdn.microsoft.com/en-us/magazine/bb985010.aspx

[2] http://en.wikipedia.org/wiki/Memory_leak

这篇关于C#活动内存泄漏的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆