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

Mar*_*ram 178 .net c# garbage-collection event-handling

如果我有以下代码:

MyClass pClass = new MyClass();
pClass.MyEvent += MyFunction;
pClass = null;
Run Code Online (Sandbox Code Playgroud)

pClass会被垃圾收集吗?或者它会在它们发生的时候仍然停止发射?我是否需要执行以下操作才能进行垃圾回收?

MyClass pClass = new MyClass();
pClass.MyEvent += MyFunction;
pClass.MyEvent -= MyFunction;
pClass = null;
Run Code Online (Sandbox Code Playgroud)

Mar*_*ell 199

对于特定问题"将pClass收集垃圾":事件订阅对pClass(作为发布者)的集合没有影响.

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

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

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

publisher.SomeEvent += target.SomeHandler;
Run Code Online (Sandbox Code Playgroud)

然后"发布者"将保持"目标"活着,但"目标"不会让"发布者"保持活力.

所以没有:如果要收集pClass,则无需取消订阅听众.但是,如果pClass是长寿命(比MyFunction的实例更长),然后pClass可以保持该实例活着,所以它如果要收集目标有必要取消.

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

  • 好吧,如果问题是"将pClass收集垃圾",那么答案"它取决于是否......"实际上并不正确.它不依赖于任何东西,因为Marc自己进一步指出了这一点. (6认同)

Tor*_*gen 8

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

所以不,你不必分离处理程序,以便pClass被垃圾收集.


小智 7

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

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