您的位置:首页 > 其它

.net 垃圾回收学习【Memory leak via event handlers】【翻译&&学习】

2011-08-27 18:07 447 查看
From: http://blogs.msdn.com/b/abhinaba/archive/2009/05/05/memory-leak-via-event-handlers.aspx

分享一下我们的客户最近比较感兴趣的内存溢出的问题。

The short version

问题的核心是他们有Event sinks和Sources。 Event sinks被正确的释放,然而,在释放的过程中他们忘记了从触发事件的source中移除event sink.所以,事实上,已经被释放掉的sinks仍然可以从event source被reachable。所以GC不会释放Event sinks并且会导致泄漏的对象。

Now the not-so-long version

考虑如下代码,这里有EventSource和EventSink对象,EventSource对外公开SomeEvent事件,Sink可以订阅此事件。

EventSink sink = new EventSink();

EventSource src = new EventSource();


src.SomeEvent += sink.EventHandler;

src.DoWork();


sink = null;

// Force collection

GC.Collect();

GC.WaitForPendingFinalizers();

在以上的代码中假如你为EventSink添加一个Finaizer方法的话,然后在Finalizer方法中添加一个端点或者控制台输出的话,你会发现它永远不会触发,即使你将Sink设置为NULL。原因是在第三行我们将sink添加到了Source的Invoke list上了。所以即使sink被设置为NULL,最初的对象依然是可以从Src reachable的。

+=操作执行的时候将sink添加到了对象的触发列表中,当把sink设置为NULL的时候,Sink的老对象仍然在内存中,导致内存不停的增大,最终在某个点会导致崩溃。

修复的方法是确保移除了sink.

EventSink sink = new EventSink();

EventSource src = new EventSource();

src.SomeEvent += sink.EventHandler;

src.DoWork();

src.SomeEvent -= sink.EventHandler;

sink = null;

上面的代码只是一个示例,显然你不应该在多处进行Event的Add,remove操作。确保EventSink实现了IDisposable模式,将+=,-=操作封装在ctor/dispose中。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐