2

在以下程序中...

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实例的引用,所以我可以不引用它。我在调试时没有遇到任何问题。但是现在我担心当应用程序长时间运行并且垃圾收集器更加活跃时,部署后可能会出现问题。

4

3 回答 3

5

Handler在删除对该对象的所有引用之前,不会对您的类的实例化对象进行垃圾收集。

因此,在您取消订阅所有事件处理程序之前,该对象将存在。因为订阅的事件处理程序也是连接Parent实例和Handler实例的另一个“引用”。

是否有可能,在程序运行一段时间后,垃圾收集器可能会决定消除 Handler 实例,因此每当引发 parent.SomeEvent 时将不再调用其 parent_SomeEvent 处理程序?

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

此外,GC 足够智能,可以确定未引用对象(未引用岛)的隔离池。因此,在这种情况下,您的父对象也未被引用,GC 将确定整个对象链(Parent对象、event订阅和handler对象)未被引用,并将在下一个收集周期将它们全部收集起来。

如果可以,我会推荐这篇 MSDN文章。让您对 .NET 中垃圾收集的广泛概念有一个很好的概述。在编码时牢记非常有用。

于 2013-03-12T19:38:27.363 回答
3

Program一直存在,它引用 Parent 的一个实例因此Parent永远不会被垃圾收集(直到程序结束)。

Parent通过其事件处理程序SomeEvent保留一组委托,因此其中的任何委托都不会被垃圾收集。

所以简而言之,不,它不会被垃圾收集。

于 2013-03-12T19:40:02.033 回答
2

当您运行程序时,Parent该类包含对EventHandler您在Handler构造函数中创建的委托实例的引用,而委托实例包含对该Handler实例的引用。所以Handler只要有对实例的引用,实例就不会被垃圾回收Parent

于 2013-03-12T19:40:02.943 回答