这是一个关于 C#/.NET 中对象终结和收集的学术问题。背景阅读是 C# 语言规范“自动内存管理”的第 3.9 节。
当没有对对象的显式引用时,它可能会被垃圾收集。它变得“有资格被销毁”。在将来的某个时刻(例如,如果强制垃圾收集),将运行对象的析构函数。
在析构函数中,如果保存对该对象的引用,该对象将被最终确定,但不符合收集条件。这可能导致对象处于已完成但未收集的状态。规范的第 3.9 节有一个这样的例子。
此时,该对象确实还活着,因为它尚未被垃圾收集。但是,引用该对象的 WeakReference 报告 IsAlive 值为 false,表明该对象已被收集。
核心问题是——IsAlive 属性真正报告的是什么?我们知道我们不能信任此属性的 true 值,因为在您读取该值后不久该值可能会变为 false。但 false 值是值得信赖的,并且意味着(根据文档)该对象已被垃圾收集。那么在这种情况下 IsAlive 属性告诉我们什么呢?严格来说,对象是否已被垃圾回收并不严格,因为我们认为该对象处于最终确定但未回收的状态。
这是展示该行为的示例。
public class Dog
{
public static Dog KeepDogRef;
public string Name { get; set; }
public Dog(string name)
{
Name = name;
}
~Dog()
{
Console.WriteLine("Dog destructor for " + Name + " called");
Dog.KeepDogRef = this;
}
public void Bark()
{
Console.WriteLine(Name + " : Woof");
}
}
以及主程序的代码。如果运行代码,您将看到原始 WeakReference 报告 IsAlive 为 false,即使在我们重构对象之后也是如此。
static void Main()
{
Dog dog = new Dog("Bowser");
WeakReference dogRef = new WeakReference(dog);
// Unref Bowser, now eligible for destruction
dog = null;
GC.Collect();
GC.WaitForPendingFinalizers();
// Bowser no longer alive
Console.WriteLine(string.Format("Object still alive: {0}", dogRef.IsAlive));
// Bowser alive again
Dog newRef = Dog.KeepDogRef;
newRef.Bark();
}
}