jnv*_*jgt 27 .net c# events weak-references
有两种方法(我知道)在C#中导致无意的内存泄漏:
IDisposable
我真的不明白第二点.如果源对象的生命周期比侦听器长,并且当没有其他引用时,侦听器不再需要事件,则使用普通的.NET事件会导致内存泄漏:源对象将侦听器对象保存在内存中应该是垃圾收集.
你能用C#中的代码解释事件如何导致内存泄漏,以及如何使用弱引用和没有弱引用来编写代码来解决它?
Fre*_*örk 35
当侦听器将事件侦听器附加到事件时,源对象将获得对侦听器对象的引用.这意味着在分离事件处理程序或收集源对象之前,垃圾收集器无法收集侦听器.
考虑以下类:
class Source
{
public event EventHandler SomeEvent;
}
class Listener
{
public Listener(Source source)
{
// attach an event listner; this adds a reference to the
// source_SomeEvent method in this instance to the invocation list
// of SomeEvent in source
source.SomeEvent += new EventHandler(source_SomeEvent);
}
void source_SomeEvent(object sender, EventArgs e)
{
// whatever
}
}
Run Code Online (Sandbox Code Playgroud)
...然后是以下代码:
Source newSource = new Source();
Listener listener = new Listener(newSource);
listener = null;
Run Code Online (Sandbox Code Playgroud)
尽管我们分配null
到listener
,它不会被垃圾收集,因为newSource
目前仍持有的引用,事件处理程序(Listener.source_SomeEvent
).要解决此类泄漏,在不再需要事件侦听器时始终分离事件侦听器非常重要.
编写上述示例以关注泄漏问题.为了修复该代码,最简单的方法可能是Listener
保持对引用的引用Source
,以便以后可以分离事件监听器:
class Listener
{
private Source _source;
public Listener(Source source)
{
_source = source;
// attach an event listner; this adds a reference to the
// source_SomeEvent method in this instance to the invocation list
// of SomeEvent in source
_source.SomeEvent += source_SomeEvent;
}
void source_SomeEvent(object sender, EventArgs e)
{
// whatever
}
public void Close()
{
if (_source != null)
{
// detach event handler
_source.SomeEvent -= source_SomeEvent;
_source = null;
}
}
}
Run Code Online (Sandbox Code Playgroud)
然后调用代码可以发信号通知它是使用对象完成的,这将删除Source
对'Listener` 的引用;
Source newSource = new Source();
Listener listener = new Listener(newSource);
// use listener
listener.Close();
listener = null;
Run Code Online (Sandbox Code Playgroud)