2010-09-07 78 views
6

如果是,是否有办法在全局解除所有有线事件的接线无线事件是内存泄漏吗?

编辑:例如说。我有对象,每个标记与事件如orm.NatureChanged += Nature_Changed;我标记这些事件时,我创建每个orm实例。如果我没有通过像orm.NatureChanged -= Nature_Changed;这样的手段断线,它会导致内存泄漏吗?

+0

你在问什么? – SLaks 2010-09-07 18:24:30

+2

你的意思是一个不会无线连接的事件吗? – Bobby 2010-09-07 18:24:42

+0

您是否询问有空调用列表的事件/委托? – Oded 2010-09-07 18:26:32

回答

5

没有,因为当你无线化的情况下,委托(它是一个对象),其连接到该事件是

这次谈话对这个问题会谈不再扎根,并且在GC认为适当的时候收集。这当然假设事件委托没有附加到多个处理程序,在这种情况下,直到它从所有事件中解除连接才会被收集。

+0

太棒了!那么,是否有任何方法可以在全球范围内放弃多个处理程序? – 2010-09-07 18:46:45

+1

@Avatar:除非您使用反射(并且不这样做),否则无法从声明类之外访问事件的调用列表。所以不行。 – 2010-09-07 18:50:04

+2

我想你可以想出一些手动跟踪哪个事件被连接到哪里,但这会变得很繁琐,而且你真的不会从中获得太多。你可能会浪费更多的跟踪事件的内存来展开它,而不是让它成为事件,并让gc在需要时处理它。 – kemiller2002 2010-09-07 18:54:30

2

这不是一个内存泄漏,它只是不挂钩任何处理程序,如果他们没有连接,自动或其他。所以这个事件对任何人都没有影响,得到清理,生活还在继续。 How do events cause memory leaks in C# and how do Weak References help mitigate that?

看到一些背景信息在这里:What does AutoEventWireUp page property mean?

+0

3662842链接真棒。确实很棒。我正在考虑询问在回答会议中解释过的lister = null。这真的很有用。 – 2010-09-08 16:04:37

6

无论你问什么,你的问题的技术答案是“不”。从技术上讲,除非在CLR中发现错误,否则管理对象并不存在真正的“内存泄漏”(这是使它们成为好东西的重要组成部分)。要回答什么,我想你实际上是在问,不过,这听起来像你问的两两件事之一:

  1. 有什么需要可以与不附加有任何委托事件做?
  2. 事件是否可以防止垃圾收集器清理对象?

第一个问题的答案只是“不”。移动,没有什么可以在这里看到。

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

也就是说,我有两个对象:生产者和消费者。生产者发起消费者消费的事件。

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) 
    { 
     // ... 
    } 
} 

在这个例子中,在AttachTo被称为仍将可达至于GC的Consumer任何实例关注,直到Producer它十分重视是符合回收的情况下,因为后面的执行委托OmgIDidSomething事件具有对应的Consumer实例的引用。

+0

我的问题是你上面提到的第二个问题。 – 2010-09-07 18:44:00

2

如果你的意思是否是没有得到事件未连线可能会导致内存泄漏,得到的答案是,它可以持有,如果事件委托对象的实际寿命远远长于物体的使用寿命代表参考的内容。例如,如果一个集合的枚举器挂钩了一个CollectionChanged事件,并且有人在没有配置它们的情况下获得枚举器,那么每当枚举集合被枚举时(不需要处理枚举器),就会创建一个新的枚举器对象,该对象会一直保留在内存中作为基础收集。