【发布时间】:2019-01-17 10:31:41
【问题描述】:
事件处理程序很容易导致内存泄漏,因为事件的调用列表持有对事件处理实例的引用,因此如果事件源还活着,事件处理实例就不能被垃圾回收。
但请考虑以下代码:
public class SomeClass
{
public event EventHandler SomeEvent;
}
public class MyClass
{
public MyClass(SomeClass source)
{
//VERSION 1
source.SomeEvent += OnSomeEvent;
//VERSION 2
void localHandler(object s, EventArgs args) { Console.WriteLine("some action with(out) any references"); }
source.SomeEvent += localHandler;
//VERSION 3
var x = new object();
source.SomeEvent += (s, e) => { Console.WriteLine("some event fired, using closure x:" + x.GetHashCode()); };
//VERSION 4
source.SomeEvent += (s, e) => { Console.WriteLine("some action without any references"); };
}
private void OnSomeEvent(object sender, EventArgs e)
{
//...
}
}
我的假设/问题为什么不同的事件处理版本可能导致内存泄漏:
- 版本 1:因为调用目标明确引用了
MyClass的实例。 - 版本 2:因为对
localHandler的引用意味着对MyClass实例的引用——除非localHandler中的代码没有对MyClass实例的引用? - 版本 3:因为 lambda 包含一个闭包,它本身是对
MyClass实例的引用 - 或者是吗? - 版本 4:因为 lambda 没有引用
MyClass的实例,这可能不会导致泄漏?
还有,版本 3 和 4 的后续问题:
- .Net 为存储的 lambda/闭包创建的“魔术助手对象”在哪里,它是否(总是)包含一个可以使
MyClass的实例保持活动状态的引用? - 如果 lambda 事件处理程序可能泄漏,它们应该只在不存在问题的情况下使用(例如,
MyClass实例比SomeClass实例寿命更长),因为它们无法使用-=删除?
编辑: 这篇文章(原标题为“事件处理程序何时会导致内存泄漏?”)被建议作为 Why and How to avoid Event Handler memory leaks? 的副本,但我不同意,因为问题是针对的特别是在 lambda 事件处理程序中。我改写了问题/标题以使这一点更清楚。
【问题讨论】:
-
我不认为它是重复的,因为我的问题超出了您链接中的问题,特别要求将 lambdas 作为事件处理程序。
标签: c# events memory-leaks