使用活动事件处理程序对未引用对象进行垃圾收集

本文关键字:对象 引用 活动 事件处理 程序 | 更新日期: 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实例就不会被垃圾收集。