C#活动内存泄漏 [英] C# Events Memory Leak
问题描述
在做这些退订事件发生内存泄漏?我应该写析构函数或实现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屋!