C# 事件处理程序是否阻止垃圾收集的发生?

C# 事件处理程序是否阻止垃圾收集的发生?,c#,.net,event-handling,garbage-collection,C#,.net,Event Handling,Garbage Collection,如果我有以下代码: MyClass pClass = new MyClass(); pClass.MyEvent += MyFunction; pClass = null; pClass会被垃圾收集吗?或者,它会在事件发生时继续发射信号吗?为了允许垃圾收集,我需要执行以下操作吗 MyClass pClass = new MyClass(); pClass.MyEvent += MyFunction; pClass.MyEvent -= MyFunction; pClass = null; 对

如果我有以下代码:

MyClass pClass = new MyClass();
pClass.MyEvent += MyFunction;
pClass = null;
pClass会被垃圾收集吗?或者,它会在事件发生时继续发射信号吗?为了允许垃圾收集,我需要执行以下操作吗

MyClass pClass = new MyClass();
pClass.MyEvent += MyFunction;
pClass.MyEvent -= MyFunction;
pClass = null;
对于特定的问题“pClass是否会被垃圾收集”:事件订阅对pClass的收集没有影响(作为发布者)

对于一般的GC(特别是目标):这取决于MyFunction是静态的还是基于实例的

实例方法的委托(如事件订阅)包括对实例的引用。因此,是的,事件订阅将阻止GC。但是,一旦发布事件的对象(上面的pClass)符合收集条件,这就不再是一个问题

请注意,这是单向的;i、 e.如果我们有:

publisher.SomeEvent += target.SomeHandler;
然后“publisher”将使“target”保持活动状态,但“target”不会使“publisher”保持活动状态

所以没有:如果pClass无论如何都要被收集,那么就没有必要取消听众的订阅。但是,如果pClass是长寿命的(比使用MyFunction的实例更长),那么pClass可以使该实例保持活动状态,因此如果希望收集目标,则有必要取消订阅


但是,由于这个原因,当与基于实例的处理程序一起使用时,静态事件非常危险。

是的,
pClass
将被垃圾收集。事件订阅并不意味着存在对
pClass
的任何引用


因此,不必为了垃圾收集
pClass
而分离处理程序。

当一段内存不再被引用时,它就成为垃圾收集的候选对象。当类的实例超出范围时,程序将不再引用它。它不再使用,因此可以安全地收集


如果你不确定某样东西是否会被收集,问自己以下问题:是否仍然存在对它的引用?事件处理程序由对象实例引用,而不是反过来引用。

pClass
将被垃圾收集。但是,如果上面的代码片段位于另一个类中,那么如果您没有将
pClass
设置为
null

,则该类的实例可能不会被清除。如果问题是“pClass是否会被垃圾收集”,那么答案“这取决于…”实际上是不正确的。它不依赖于任何东西,正如马克自己进一步指出的那样。@Tor-足够公平-我要澄清的是,尽管事件订阅委托仅指出一种方式,但如果订阅者在完成某个事件后打算取消订阅,则需要某种形式的发布者参考。这可能是一个
WeakReference
,在某些情况下,这可能是一个好主意,但往往不是一个好主意。这是一个很好的答案,因为它还解决了问题的另一半(没有被问到):出版商将阻止订阅人成为GC'd。是的,正如@BobSammers所说,如果一个生命周期短的实例(如窗体/窗口)订阅了一个生命周期长的服务(如提供数据的单例),那么这可能真的是一个问题。例如:单例会保留一个引用,而对象会保留在内存中,即使我们认为它们已卸载!所以在使用事件时要非常小心。我们在大型软件中滥用了事件,之后很难解决。我将试探性地向对此问题感兴趣的读者建议,可能值得熟悉轻量级事件/弱事件模式,它们不会阻止垃圾收集的发生。这一主题的一个很好的引导方法是留待后人注意:将引用设置为null只会通过将引用的范围扩展一行来延迟垃圾收集器。NET不是VB6。