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


183

如果我有以下代码:

MyClass pClass = new MyClass();
pClass.MyEvent += MyFunction;
pClass = null;

pClass会被垃圾回收吗?还是会在事件发生时仍在触发事件呢?我是否需要执行以下操作才能进行垃圾回收?

MyClass pClass = new MyClass();
pClass.MyEvent += MyFunction;
pClass.MyEvent -= MyFunction;
pClass = null;

11
我将向对这个问题感兴趣的读者尝试性地建议,可能值得熟悉轻量级事件/弱事件模式,这不会阻止垃圾回收的发生。一个好的SO引导到这个话题stackoverflow.com/questions/185931/...
fostandy

20
后代注意事项:将引用设置为null只是通过将引用范围扩大一行来延迟垃圾回收器。.NET不是VB6。
约翰·桑德斯

Answers:


207

对于特定的问题“ pClass会被垃圾收集”:事件订阅对pClass的收集(作为发布者)没有影响。

对于一般的GC(尤其是目标):它取决于MyFunction是静态的还是基于实例的。

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

请注意,这是单向的;即如果我们有:

publisher.SomeEvent += target.SomeHandler;

那么“发布者”将使“目标”保持活动状态,但“目标”将使“发布者”保持活动状态。

所以不能:如果无论如何都要收集pClass,则无需取消订阅侦听器。但是,如果pClass是长寿命(比MyFunction的实例更长),然后pClass可以保持该实例活着,所以需要退订,如果你想收集的对象。

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


6
好吧,如果问题是“ pClass是否会被垃圾回收”,那么答案“取决于...是否”实际上是不正确的。正如马克本人所说的那样,它不依赖任何东西。
Tor Haugen

@Tor-足够公平-我会澄清
Marc Gravell

尽管事件订阅委托仅指出了一种方式,但打算在完成事件后取消订阅事件的订阅者将需要某种形式的对发布者的引用。这WeakReference可能是一个好主意,在某些情况下可能是个好主意,但在很多情况下却不是一个好主意。
supercat 2012年

一个很好的答案,因为它也解决了问题的另一半(未问):发布者将阻止订阅者被GC。
Bob Sammers,

是的,正如@BobSammers所说,如果短寿命实例(例如Form / Window)订阅了寿命较长的服务(例如提供数据的Singleton这样的服务),这可能确实是一个问题:Singleton然后保留引用并且,即使我们认为对象已卸载,对象也因此保留在内存中!所以在使用事件时要非常谨慎。我们滥用大型软件的事件,事后很难解决。
Elo

9

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

不能,您不必分离处理程序即可对pClass进行垃圾收集。


8

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

如果您不确定是否会收集到一些东西,请问自己以下问题:是否仍然存在对此的引用?事件处理程序由对象实例引用,而不是相反。


0

pClass将被垃圾收集。但是,如果上面的代码段位于另一个类中,那么如果您未将其设置pClass为,则可能不会清除该类的实例null

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.