7
public class MyClass {
  private static MyClass heldInstance;

  public MyClass() {
    heldInstance = this;
  }
}

假设 MyClass 的实例没有以任何其他方式植根,这里的私有静态引用会阻止它被垃圾收集吗?

4

2 回答 2

9

您发布的课程不会被垃圾收集。你可以通过给它一个带有控制台输出的终结器来测试它:

public class MyClass
{
    private static MyClass heldInstance;
    public MyClass()
    {
        heldInstance = this;
    }
    ~MyClass()
    {
        Console.WriteLine("Finalizer called");
    }
}
class Program
{
    static void Main(string[] args)
    {
        var x = new MyClass(); // object created

        x = null; // object may be eliglible for garbage collection now

        // theoretically, a GC could happen here, but probably not, with this little memory used
        System.Threading.Thread.Sleep(5000);

        // so we force a GC. Now all eligible objects will definitely be collected
        GC.Collect(2,GCCollectionMode.Forced);

        //however their finalizers will execute in a separate thread, so we wait for them to finish
        GC.WaitForPendingFinalizers();

        System.Threading.Thread.Sleep(5000);
        Console.WriteLine("END");

    }
}

输出将是:

END
Finalizer called

这意味着该类仅在应用程序的最终拆卸时被收集,而不是在常规垃圾收集期间。

如果您像这样创建此类的多个实例:

var x = new MyClass();
x = new MyClass();
x = new MyClass();
x = new MyClass();

那么除了最近的一个都将被垃圾收集。

你会得到

Finalizer called
Finalizer called
Finalizer called
END
Finalizer called
于 2013-02-26T21:51:04.953 回答
2

垃圾收集器确定哪些对象是可访问的,并将收集那些不可访问的。为了确定一个对象是否可达,收集器将从所谓的开始。其中的根是当前在评估堆栈上的东西,还有静态字段。收集器将遵循对对象的引用,从根到任何对象,从这样的对象到任何其他对象,依此类推。以这种方式访问​​过的每个对象都是可访问的,因此将保持活动状态。

在您的情况下,静态字段是垃圾收集器的根之一,因此它永远不会收集该字段(间接)引用的任何对象。但是,如果您将该字段设置为,null则该字段不再引用该实例,并且可能会收集该实例。

于 2013-02-26T21:57:32.850 回答