gpt4 book ai didi

c# - 事件如何导致 C# 中的内存泄漏以及弱引用如何帮助缓解这种情况?

转载 作者:IT王子 更新时间:2023-10-29 04:16:15 26 4
gpt4 key购买 nike

有两种方式(据我所知)会导致 C# 中的意外内存泄漏:

  1. 不释放实现IDisposable的资源
  2. 错误地引用和取消引用事件。

第二点我不是很明白。如果源对象的生命周期比监听器长,并且监听器在没有其他引用时不再需要事件,则使用普通的 .NET 事件会导致内存泄漏:源对象在内存中保存监听器对象应该被垃圾收集。

您能否解释一下事件如何导致 C# 中的代码发生内存泄漏,以及我如何使用弱引用和不使用弱引用来编写代码来绕过它?

最佳答案

当监听器将事件监听器附加到事件时,源对象将获得对监听器对象的引用。这意味着在分离事件处理程序或收集源对象之前,垃圾收集器无法收集监听器。

考虑以下类:

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
}
}

...然后是以下代码:

Source newSource = new Source();
Listener listener = new Listener(newSource);
listener = null;

即使我们将 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;
}
}
}

然后调用代码可以发出信号表明它已使用该对象完成,这将删除 Source 对 ´Listener` 的引用;

Source newSource = new Source();
Listener listener = new Listener(newSource);
// use listener
listener.Close();
listener = null;

关于c# - 事件如何导致 C# 中的内存泄漏以及弱引用如何帮助缓解这种情况?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3662842/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com