【问题标题】:What's circular reference destruction sequence什么是循环引用销毁序列
【发布时间】:2015-02-11 09:26:45
【问题描述】:

这里我声明了两种类型 A 和 B,它们相互引用

public class A
{
    public B B { get; set; }

    ~A()
    {
        Console.WriteLine( "destructing A..." );
    }
}

public class B
{
    public A A { get; set; }

    ~B()
    {
        Console.WriteLine( "destructing B..." );
    }
}

在Main方法中,

    var b = new B();
    var a = new A();
    a.B = b;
    b.A = a;
    a = null;
    b = null;
    GC.Collect();

输出显示销毁顺序和他们定义的顺序完全一样,不知道为什么?

【问题讨论】:

    标签: c# circular-reference


    【解决方案1】:

    终结者没有保证顺序:

    不保证两个对象的终结器以任何特定顺序运行,即使一个对象引用另一个对象。也就是说,如果对象 A 具有对对象 B 的引用并且两者都有终结器,那么当对象 A 的终结器启动时,对象 B 可能已经被终结。 Object.Finalize

    关键终结器除外:

    此外,CLR 在普通终结器和关键终结器之间建立了弱排序:对于同时被垃圾回收回收的对象,所有非关键终结器都会在任何关键终结器之前调用。 CriticalFinalizerObject

    【讨论】:

    • 非常感谢,我猜我之前的错误结论是基于有限的实验。所以我们永远不应该编写假设销毁顺序的代码,而是直接将 IDispose 用于非托管资源而不是 finalizer。
    • @user1784779 我会这样说:我们永远不应该在假设的情况下编写代码,如果可能的话,我们应该依赖文档。即使您总是观察到相同的行为,也可能只是实现细节,但不能保证。
    【解决方案2】:

    .NET 中的垃圾收集是不确定的(正如您在调用 GC.Collect 后所观察到的那样)。不保证最终确定的顺序。

    是的,这意味着被引用的对象可以在引用它们的对象之前完成。这就是编写终结器非常困难的原因之一。您可能会在“未初始化”状态下工作。

    尽量不要使用终结器。很少需要它们。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-08-27
      • 2011-04-13
      • 1970-01-01
      • 1970-01-01
      • 2014-06-03
      • 2012-01-30
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多