使用活动事件处理程序对未引用对象进行垃圾收集
本文关键字:对象 引用 活动 事件处理 程序 | 更新日期: 2023-09-27 18:03:29
在下列程序中…
using System;
class Program
{
static Parent parent;
static void Main( string[] args )
{
parent = new Parent();
// The program hereafter runs for a long time and occasionally
// causes parent.SomeEvent to be raised.
}
}
class Parent
{
public event EventHandler SomeEvent;
public Parent()
{
new Handler( this );
}
}
class Handler
{
public Handler( Parent parent )
{
parent.SomeEvent += parent_SomeEvent;
}
void parent_SomeEvent( object sender, EventArgs e )
{
// Does something important here.
}
}
注意,实例化的Handler
对象没有被引用,尽管它已经订阅了SomeEvent
。是否有可能,在程序运行一段时间后,垃圾收集器可能决定消除Handler
实例,因此每当parent.SomeEvent
被引发时,它的parent_SomeEvent
处理程序将不再被调用?
我需要这个澄清我正在写的应用程序。如上所示,有许多类似Handler
的对象被实例化,但没有被引用。Handler
的主要目的是订阅SomeEvent
。没有有用的方法可以调用对Handler
实例的引用,所以我可以不引用它。我在调试时没有遇到任何问题。但是现在我担心的是,当应用程序长时间运行并且垃圾收集器更活跃时,部署后可能会出现问题。
Handler
类的实例化对象将不会被垃圾收集,直到对该对象的所有引用被删除。
因此,在您取消订阅所有事件处理程序之前,对象将一直存在。因为订阅的事件处理程序也是将Parent
实例连接到Handler
实例的另一个"引用"。
有没有可能,在程序运行了一段时间后垃圾收集器可能决定消除Handler实例及其因此,无论何时,parent_SomeEvent处理程序将不再被调用家长引发了什么事件?
这就是为什么GC只从堆中收集"未引用"对象的原因。您的场景将导致未定义的NullReferenceException
s,完全取决于GC何时决定删除对象。所以幸运的是,情况并非如此:).
此外,GC足够智能,可以确定未引用对象的隔离池(未引用孤岛)。因此,在这种情况下,您的父对象也未被引用,那么GC将确定整个对象链(Parent
对象、event
订阅和handler
对象)未被引用,并在下一个收集周期中将它们全部收集在一起。
如果可以的话,我推荐这篇MSDN文章。让您对。net中垃圾收集的广泛概念有一个很好的概述。在编码时记住这一点非常有用。
Program一直存在,并且它引用了Parent的一个实例,因此Parent永远不会被垃圾收集(直到程序结束)。
Parent通过其事件处理程序SomeEvent保存委托集合,因此其中的任何委托都不会被垃圾收集。
所以简而言之,不,它不会被垃圾收集。
当您运行程序时,Parent
类保存对您在Handler
构造函数中创建的EventHandler
委托实例的引用,而委托实例保存对Handler
实例的引用。因此,只要存在对Parent
实例的引用,Handler
实例就不会被垃圾收集。