繁体   English   中英

c#中的垃圾收集误区

[英]Garbage Collection misunderstanding in c#

我搜索谷歌没有得到我想要的东西。 我不知道我是对还是错。 看,我试图了解GC.Collect()所以这里是代码..

public class SomePublisher
{
    public event EventHandler SomeEvent;
}

public class SomeSubscriber
{
    public static int Count;

    public SomeSubscriber(SomePublisher publisher)
    {
        publisher.SomeEvent += new EventHandler(publisher_SomeEvent);
    }

    ~SomeSubscriber()
    {
        SomeSubscriber.Count++;
    }

    private void publisher_SomeEvent(object sender, EventArgs e)
    {
        // TODO: something
    }
}

我在我的主线程中这样做..

 SomePublisher publisher = new SomePublisher();

        for (int i = 0; i < 10; i++)
        {
            SomeSubscriber subscriber = new SomeSubscriber(publisher);
            subscriber = null;
        }

        GC.Collect();
        GC.WaitForPendingFinalizers();

        Console.WriteLine(SomeSubscriber.Count.ToString());
        Console.ReadLine();

我得到输出0,但根据我应该是10,因为GC.Collect()必须从内存中删除class1对象,所以必须调用class1析构函数,所以计数必须增加到10 ..可以任何正文解释这个..

(另请注意,C#没有析构函数1 ,它有终结器。这些是非常不同的东西,你不应该混淆它们。)

“问题”就在这条线上:

publisher.SomeEvent += new EventHandler(publisher_SomeEvent);

这将创建一个以特定对象实例的publisher_SomeEvent()方法为目标的委托,并将此委托添加到publisher.SomeEvent事件的调用列表中。 此委托对象引用目标对象,并阻止对象的收集! (这是一件好事 - 如果您将委托委托给特定对象上的方法,那么在不再引用委托之前,您不希望收集该对象。)

这在技术上根本不是问题,而是运行时保持对象仍然存在仍然被引用。

为了说明,这是参考链:

SomePublisher -+-> EventHandler --> SomeSubscriber
               |
               +-> EventHandler --> SomeSubscriber
               |
               +-> (Eight more...)

在调用GC.Collect()之前,您需要执行以下两项操作之一:

  1. 在释放每个SomePublisher对象之前取消订阅该事件。 这将使EventHandler委托实例和它们引用的SomeSubscriber实例都有资格进行收集。
  2. 设置publisher = null; 这将导致整个对象图符合收集条件。

在这两种情况下,这将释放对SomeSubscriber对象的所有引用。


1请注意,C#规范确实将这些代码块称为“析构函数”,但这是一个可怕的名称。 那些熟悉垃圾收集语言的人会对它感到困惑,因为“终结器”是垃圾收集器在不再可以访问对象时调用的代码的广泛术语。 特别是C ++开发人员会期望析构函数在不同的时间执行。 所以是的,C#有一个叫做“析构函数”的东西,但它不是一个析构函数。 (说些什么不是这样!)

SomeSubcriber对象的终结器直到最后才会被调用。 因为即使SomeSubscriber对象设置为null,它的内存仍然被SomePublisher对象的事件SomeEvent引用,该对象在应用程序结束之前一直存在。 因此,当调用GC.Collect()时,垃圾收集器将找不到要放入终结器队列的任何对象。

public SomeSubscriber(SomePublisher publisher)
{
// publisher.SomeEvent += new EventHandler(publisher_SomeEvent);
}

如果我们可以通过上面的代码替换SomeSubcriber的构造函数,那么我们将在控制台中将结果作为10。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM