【问题标题】:Why does inheriting from System.ComponentModel.Component prevent object from being garbage collected (at all)为什么从 System.ComponentModel.Component 继承会阻止对象被垃圾收集(完全)
【发布时间】:2013-09-03 07:27:49
【问题描述】:

我最初的问题是在继承自例如的类中取消注册自引用事件处理程序是否重要。零件。他们提供了一个 Disposed 事件,在该事件中可以取消初始化。

但我在玩它并意识到一些奇怪的事情:从 System.ComponentModel.Component 派生确实阻止了析构函数被调用(即使在应用程序结束时也是如此。

这是一个显式使用 GC.Collect 强制收集的示例(仅用于测试,从不在产品代码中使用它)

using System;
using System.ComponentModel;

namespace CSharpEventHandlerLifetime
{
    public class LongLiving : Component
    {

        public LongLiving()
        {
            Console.WriteLine("Creating object");
            // Disposed += (sender, args) => Console.WriteLine("Disposed");
        }

        ~LongLiving()
        {
            Console.WriteLine("Destructor called");
        }

    }

    class Program
    {
        public static void _create()
        {
            using (var l = new LongLiving())
            {
                Console.WriteLine("Generation is {0}", GC.GetGeneration(l));
            }
        }

        static void Main(string[] args)
        {
            _create();

            GC.Collect(); // this should call dtor of LongLiving


            Console.ReadKey(); // wait before end
        }
    }
}

当我完全删除继承的 Component 类(将 using 更改为普通的 new)或将其替换为 IDisposable(并实现一些空的 Dispose 方法)时,我清楚地看到调用 GC.Collect 调用了 LongLiving 的 dtor。

我不理解这种行为,因为我至少希望在应用程序退出时会闯入 ~dtor,但从 Component 派生时它永远不会发生。

【问题讨论】:

  • 请注意,Finalizable 对象不会通过单个 GC 进行垃圾收集。它们会一直存活到下一次垃圾回收。
  • @SimonWhitehead - 是的,但他们在第一次收集中幸存下来,正是因为他们的终结者已经安排好了。因此,如果它们幸存下来,并且它们是等待被终结的极少数对象之一,那么终结器不执行(在合理的时间范围内,终结器线程没有以某种方式阻塞等)仍然会令人惊讶
  • 您能否详细说明“单次 GC 不会收集垃圾”。如果应用程序存在,下一次垃圾收集是什么。然而,SuppressFinalize 对我来说听起来更清楚。
  • @Damien 我的意思是这样,因为你不能保证什么时候会......测试有缺陷。
  • @SimonWhitehead - 但测试的解决方法是插入对WaitForPendingFinalizers 的调用,而不是立即运行第二个集合,这就是您的第一条评论所暗示的将解决问题。

标签: c# garbage-collection


【解决方案1】:

Component 已经实现了 Disposable 模式,其中包括在完成时对GC.SuppressFinalize 的调用。当using 块退出时,会调用Dispose

所以对象被垃圾回收了,它只是永远不会调用它的终结器。

如果你有任何清理工作,你应该覆盖Dispose(bool)

例如这是Components Dispose 方法:

public void Dispose()
{
    this.Dispose(true);
    GC.SuppressFinalize(this);
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-10-08
    • 2015-04-22
    • 2015-05-04
    • 2014-03-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多