C# 在静态字段中引用自身的类可以被垃圾收集吗?
假设MyClass的实例没有以任何其他方式扎根,这里的私有静态引用会阻止它被垃圾收集吗?您发布的类不会被垃圾收集。您可以通过给它一个带有控制台输出的终结器来测试它:C# 在静态字段中引用自身的类可以被垃圾收集吗?,c#,static,garbage-collection,private,C#,Static,Garbage Collection,Private,假设MyClass的实例没有以任何其他方式扎根,这里的私有静态引用会阻止它被垃圾收集吗?您发布的类不会被垃圾收集。您可以通过给它一个带有控制台输出的终结器来测试它: public class MyClass { private static MyClass heldInstance; public MyClass() { heldInstance = this; } } 输出将是: public class MyClass { private static MyC
public class MyClass {
private static MyClass heldInstance;
public MyClass() {
heldInstance = this;
}
}
输出将是:
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();
垃圾收集器确定哪些对象是可访问的,并将收集那些不可访问的对象。要确定对象是否可访问,收集器将从所谓的根开始。根中有当前在求值堆栈上的内容,也有静态字段。收集器将跟随对对象的引用,从根到任何对象,从这样的对象到任何其他对象,依此类推。以这种方式访问的每个对象都是可访问的,因此将保持活动状态
在您的例子中,静态字段是垃圾收集器的根之一,因此它永远不会收集该字段(间接)引用的任何对象。但是,如果将该字段设置为
null
,则该字段将不再引用该实例,并且该实例可能会被收集。编辑的可能重复:简而言之,不,我认为不会。例如,在您发布的代码中,公共构造函数没有理由不具有if(heldInstance==null)
除此之外,GC一旦确定不再可访问时,将最终收集仅保留的引用从自身到自身的实例。是的,它们在AppDomain卸载之前被收集。除非类有终结器,否则这是无关紧要的。类的静态字段引用同一类的实例这一事实是无关的。静态场是根;它们将使您放入其中的任何内容保持活动状态,无论其类型如何。请注意,这是正确的,因为heldInstance
是静态的。MyClass
的实例有一个对自身的引用,这一事实没有什么特别之处。所以,是的,“引用自身的类”可以被垃圾收集。但是,示例中的类不能。
Finalizer called
Finalizer called
Finalizer called
END
Finalizer called