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

C# 使用活动事件处理程序对未引用对象进行垃圾收集,c#,.net,C#,.net,在下面的程序中 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

在下面的程序中

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.
    }
}
请注意,实例化的
处理程序
对象未被引用,尽管它已订阅
SomeEvent
。在程序运行一段时间后,垃圾收集器是否可能决定删除
处理程序
实例,因此每当引发
parent.SomeEvent
时,将不再调用其
parent\u SomeEvent
处理程序


我需要这个澄清我写的应用程序。如上图所示,有许多类似于处理程序的对象被实例化,而没有被引用。
Handler
的主要目的是订阅
SomeEvent
。没有任何有用的方法可以调用对
处理程序
实例的引用,因此我可以不引用它。调试时我没有遇到任何问题。但现在我担心,当应用程序长时间运行且垃圾收集器更活跃时,部署后可能会出现问题。

在删除对该对象的所有引用之前,不会对
处理程序的实例化对象进行垃圾收集

因此,在您取消订阅所有事件处理程序之前,对象将处于活动状态。因为订阅的事件处理程序也是另一个“引用”,它将
父类
实例连接到
处理程序
实例

程序运行一段时间后,是否可能 垃圾收集器可能决定删除处理程序实例及其 因此,无论何时都不再调用父事件处理程序 是否引发parent.SomeEvent

这正是GC只从堆中收集“未引用”对象的原因。您的场景将导致未定义的
NullReferenceException
s,完全取决于GC决定何时删除对象。幸运的是,情况并非如此:)

此外,GC足够智能,可以确定未引用对象的孤立池(未引用孤岛)。因此,在场景中,父对象也未被引用,GC将确定整个对象链未被引用(父对象<代码>父对象<代码>对象、<代码>事件订阅和<代码>处理程序对象),并将在下一个收集周期中收集它们


如果可以的话,我推荐这篇文章。让您很好地概括了.NET中垃圾收集的广泛概念。编码时要记住这一点非常有用。

程序始终存在,它引用的是父对象的一个实例,因此父对象将永远不会被垃圾收集(直到程序结束)

Parent通过其事件处理程序SomeEvent保存代理集合,因此不会对其中的任何代理进行垃圾收集


因此,简而言之,不,它不会被垃圾收集。

当您运行程序时,
父类
持有对您在
处理程序
构造函数中创建的
事件处理程序
委托实例的引用,委托实例持有对
处理程序
实例的引用。因此,只要有对
父实例的引用,就不会对
处理程序
实例进行垃圾收集。

请查看这篇文章以获得更深入的解释