如果我有以下代码:

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


pClass会被垃圾回收吗?还是会在事件发生时仍然触发事件呢?为了允许垃圾回收,我需要执行以下操作吗?

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


评论

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

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

#1 楼

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

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

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

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

publisher.SomeEvent += target.SomeHandler;


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

因此,否:如果仍然要收集pClass,则无需取消订阅侦听器。但是,如果pClass寿命长(比使用MyFunction的实例更长),则pClass可以使该实例保持活动状态,因此,如果要收集目标,则有必要取消订阅。

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

评论


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

– Tor Haugen
08年11月18日在10:09

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

– Marc Gravell♦
08年11月18日在10:54

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

–超级猫
2012年4月13日15:37

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

–鲍勃·萨默斯(Bob Sammers)
17年6月23日在18:12

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

– Elo
18-3-28的13:11

#2 楼

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

不,您不必为了分离pClass而就可以分离处理程序。

#3 楼

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

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

#4 楼

pClass将被垃圾收集。但是,如果上面的代码段在另一个类中,则如果未将pClass设置为null,则可能无法清除该类的实例。