public class MyClass {
private static MyClass heldInstance;
public MyClass() {
heldInstance = this;
}
}
假设MyClass的一个实例没有以任何其他方式生根,那么这里的私有静态引用是否会阻止它被垃圾收集?
答案 0 :(得分:8)
您发布的课程不会被垃圾收集。你可以通过给它一个带控制台输出的终结器来测试它:
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
答案 1 :(得分:2)
垃圾收集器确定哪些对象可以,并将收集那些不可用的对象。要确定对象是否可访问,收集器将以所谓的根开头。根源是当前评估堆栈中的内容,还有静态字段。收集器将跟踪从根到任何对象的对象的引用,以及从这样的对象到任何其他对象的引用,依此类推。以这种方式访问过的每个对象都是可以访问的,因此将保持活动状态。
在您的情况下,静态字段是垃圾收集器的根之一,因此它永远不会收集该字段引用(间接)的任何对象。但是,如果您将字段设置为null
,则该字段不再引用该实例,并且可以收集实例。