【问题标题】:Is unwired event a memory leak?无线事件是内存泄漏吗?
【发布时间】:2010-09-07 18:22:04
【问题描述】:

如果是,有没有办法为所有有线事件全局取消连接

编辑:比如说。我有对象,每个对象都标记有orm.NatureChanged += Nature_Changed; 之类的事件,我在创建每个 orm 实例时标记这些事件。如果我没有通过orm.NatureChanged -= Nature_Changed; 之类的方式解线,会不会导致内存泄漏?

【问题讨论】:

  • 你的意思是一个没有无线连接的事件吗?
  • 您是在询问调用列表为空的事件/代表吗?
  • @Bobby 是的。比如说。我有对象,每个对象都标记有诸如 orm.NatureChanged += Nature_Changed; 之类的事件。我在创建每个 orm 实例时标记这些事件。如果我没有通过 orm.NatureChanged -= Nature_Changed;会不会导致内存泄漏?
  • 一个新的 SO 问题很好地解决了这个问题:stackoverflow.com/questions/3662842/…

标签: c#


【解决方案1】:

无论您要问什么,对您的问题的技术回答都是“否”。从技术上讲,除非您在 CLR 中发现错误,否则托管对象不存在真正的“内存泄漏”(这是使它们成为好事的重要原因)。但是,要回答我认为您实际上在问的问题,听起来您是在问以下两件事之一:

  1. 对于没有附加任何委托的事件是否需要处理?
  2. 事件能否阻止垃圾收集器清理对象?

第一个问题的答案是“不”。继续前进,这里没什么可看的。

第二个问题的答案已经在 SO 和网络的其他领域进行了详细讨论。简短的版本是附加的事件处理程序意味着 GC 会将目标实例视为事件触发实例“可访问”。这可能导致对象在内存中保留的时间比预期的要长,因为这种可达性对用户(开发人员)来说是透明的,因为委托的构造方式。

换句话说,假设我有两个对象:生产者和消费者。 Producer 触发 Consumer...consumes 的事件。

public class Producer
{
    public event EventHandler OmgIDidSomething;
}

public class Consumer
{
    public void AttachTo(Producer producer)
    {
        producer.OmgIDidSomething += new EventHandler(producer_OmgIDidSomething);
    }

    private void producer_OmgIDidSomething(object sender, EventArgs e)
    {
        // ...
    }
}

在此示例中,就 GC 而言,调用 AttachTo 的任何 Consumer 实例都将保持可访问性,直到它附加到的 Producer 实例符合收集条件,因为在OmgIDidSomething 事件的实现具有对其对应的Consumer 实例的引用。

【讨论】:

  • 我的问题是你上面提到的第二个问题。
【解决方案2】:

不,因为当您取消连接事件时,连接到该事件的委托(它是一个对象)不再是根,并且会在 GC 认为合适时被收集。这当然是假设事件委托没有附加到多个处理程序,在这种情况下,它不会被收集,直到它与所有事件断开连接。

【讨论】:

  • 太棒了!那么,有没有办法全局展开多个处理程序?
  • @Avatar:除非您使用反射(并且不使用),否则无法从声明类外部访问事件的调用列表。所以,没有。
  • 我想你可以想出一些手动的方法来跟踪哪个事件被连接到哪里,但这会变得很麻烦,而且你真的不会从中得到太多。您可能会浪费更多的内存来跟踪事件以展开它,而不是让它在需要时让 gc 处理它。
  • @Adam Robinson 非常感谢您的快速评论。
【解决方案3】:

如果您的意思是未获得 unwired 的事件是否会导致内存泄漏,答案是如果持有事件委托的对象的实际生命周期远长于有用的委托引用的对象的生命周期。例如,如果一个集合的枚举器钩住了一个 CollectionChanged 事件,并且有人在没有释放它们的情况下获取枚举器,那么每次枚举该集合(不释放枚举器)时,都会创建一个新的枚举器对象,该对象将一直保留在内存中作为基础集合。

【讨论】:

    【解决方案4】:

    这不是内存泄漏,它只是不会将任何处理程序挂钩到该事件,如果它们没有被连接,自动或以其他方式。所以事件没有人发火,被清理干净,生活继续。

    本次对话讨论了这个主题:How do events cause memory leaks in C# and how do Weak References help mitigate that?

    在此处查看一些背景信息:What does AutoEventWireUp page property mean?

    【讨论】:

    • 3662842 链接很棒。确实很棒。我正在考虑询问答案会话中解释的 lister=null 。真的很有用。
    猜你喜欢
    • 1970-01-01
    • 2011-02-20
    • 2013-08-12
    • 2020-12-08
    • 2019-04-02
    • 2013-01-08
    相关资源
    最近更新 更多