我有这个代码:
本质上,我试图演示 c# 终结器的使用,并制作一个不会死亡的对象,我将其称为 Zombie。现在,通常这个演示效果很好,但今天我尝试使用相同的代码和对象初始值设定项,而不是仅仅分配给属性(在本例中为 Name)。我注意到有区别。也就是说,永远不会调用终结器,即使我正在尽最大努力让垃圾收集器完成它的工作。
有人可以解释一下区别吗,或者我是否发现了 C# 编译器中的错误?
(我在 Win7x64 上的 VS2010 SP1 中使用 C# 4)
谢谢。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
namespace Zombie
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Main thread: " + Thread.CurrentThread.ManagedThreadId);
// case 1: this is where the problem is located.
Zombie z = new Zombie { Name = "Guy" }; // object initializer syntax makes that the finalizer is not called.
// case 2: this is not causing a problem. The finalizer gets called.
//Zombie z = new Zombie();
//z.Name = "Guy";
WeakReference weakZombieGuyRef = new WeakReference(z, true);
z = null;
GC.GetTotalMemory(forceFullCollection: true);
GC.Collect();
while (true)
{
Console.ReadKey();
if (weakZombieGuyRef.IsAlive)
{
Console.WriteLine("zombie guy still alive");
}
else
{
Console.WriteLine("Zombie guy died.. silver bullet anyone?");
}
Zombie.Instance = null;
GC.AddMemoryPressure(12400000);
GC.GetTotalMemory(forceFullCollection: true);
GC.Collect();
}
}
}
public class Zombie
{
public string Name { get; set; }
public static Zombie Instance = null;
~Zombie()
{
Console.WriteLine(Thread.CurrentThread.ManagedThreadId);
Console.WriteLine("Finalizer called on zombie" + this.Name);
lock (typeof(Zombie))
{
Instance = this;
GC.ReRegisterForFinalize(this);
}
}
}
}
最佳答案
编辑:虽然下面的原始答案仍然准确,但看起来调试信息和优化的混合使这里有所不同。
根据我的实验:
Compiler flags Result
/o+ /debug- Finalizer runs
/o+ /debug+ Finalizer runs
/o- /debug- Finalizer runs
/o- /debug+ Finalizer does *not* run
当在命令行上使用 /o+
进行编译时,终结器仍会在我的机器上调用。我的猜测是您正在调试器中运行 - 这会改变 GC 行为。如果没有调试器,GC 将收集它可以证明永远不会被读取的任何内容。 使用调试器,我相信 GC 不会收集任何在堆栈上仍有引用的对象,即使没有代码来读取有问题的变量也是如此。 p>
现在有了对象初始值设定项,编译器代码在堆栈上包含一个额外的引用。这一行:
Zombie z = new Zombie { Name = "Guy" };
是有效的:
Zombie tmp = new Zombe();
tmp.Name = "Guy";
Zombie z = tmp;
z
的赋值仅在所有属性都已设置之后执行。
我的猜测是这里的 tmp
变量使对象保持事件状态。
关于c# - 使用Object Initializer的复活区别,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9753256/