使用对象初始化复活差异 [英] Resurrection difference in using Object Initializer

查看:98
本文介绍了使用对象初始化复活差异的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有这样的代码:



基本上我试图演示了如何使用C#终结,并作出一个对象,不能死,我把它叫做僵尸。现在,通常这个演示的伟大工程,但今天,我尝试使用的对象初始化,而不只是分配给财产(名称在这种情况下)相同的代码。我注意到是有区别的。即终结不会被调用,而不是甚至当我在尽我所能,使垃圾收集器做的工作。



有人能解释这种差异,或者我发现在C#编译器中的错误?



(I'使用C#4在Win7x64 VS2010 SP1 M)



感谢。

 使用系统; 
使用System.Collections.Generic;
使用System.Linq的;
使用System.Text;
使用的System.Threading;

命名空间僵尸
{
类节目
{
静态无效的主要(字串[] args)
{
控制台。的WriteLine(主要思路:+ Thread.CurrentThread.ManagedThreadId);

//情况1:这就是问题的所在。
僵尸Z =新的僵尸{名称=盖伊}; //对象初始化语法使得该终结不叫。

//案例2:这是不是导致问题。终结被调用。
//僵尸Z =新的僵尸();
//z.Name =人;

的WeakReference weakZombieGuyRef =新的WeakReference(Z,真);

Z = NULL;

GC.GetTotalMemory(forceFullCollection:真);

GC.Collect的();

,而(真)
{

Console.ReadKey();
如果(weakZombieGuyRef.IsAlive)
{
Console.WriteLine(僵尸家伙还活着);
}
,否则
{
Console.WriteLine(僵尸家伙死了..银弹人?);
}

Zombie.Instance = NULL;

GC.AddMemoryPressure(12400000);
GC.GetTotalMemory(forceFullCollection:真);

GC.Collect的();
}


}
}

公共类僵尸
{
公共字符串名称{;组; }
公共静态僵尸实例= NULL;

〜僵尸()
{
Console.WriteLine(Thread.CurrentThread.ManagedThreadId);
Console.WriteLine(终结呼吁僵尸+ this.Name);
锁(typeof运算(僵尸))
{
实例=这一点;

GC.ReRegisterForFinalize(本);
}
}
}
}


解决方案

编辑:虽然低于原来的答案仍然是准确的,它看起来像它的调试信息和优化,这使得这里的区别混合物。



这是我的实验:

 编译器选项结果
/ O + /调试 - 终结器运行
/ O + /调试+终结器运行
/ O- /调试 - 终结器运行
/ O- /调试+终结不*不*运行






终结仍叫上我的盒子,用命令行编​​译时 / O + 。我的猜测是,你在一个调试器中运行 - 这改变了GC行为。如果没有调试器,GC将收集任何能够证明将永远不会被读取。的的调试器,我相信GC不会收集哪还有在栈上引用的对象,即使没有的代码的阅读有问题的变量。



现在有一个对象初始化时,编译器代码包含在堆栈上额外的参考。该行:

 僵尸Z =新的僵尸{名称=盖伊}; 



是有效的:

 僵尸TMP =新Zombe(); 
tmp.Name =人;
僵尸Z = tmp目录;



分配到以Z 时,才执行 的所有属性都被设置了。



我的猜测是,这里的 TMP 变量为保持对象还活着。


I have this code:

Essentially i'm trying to demonstrate the use of the c# finalizer and make an object that cannot die, I called it Zombie. Now, normally this demo works great, but today I tried using the same code with the object initializer instead of just assigning to the property (Name in this case). I noticed there is a difference. Namely that the finalizer never gets called, not even when I'm trying my best to make the Garbage Collector do it's work.

Could someone explain the difference, or have I found a bug in the C# compiler?

(I'm using C# 4 in VS2010 SP1 on Win7x64)

Thanks.

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);
      }
    }
  }
}

解决方案

EDIT: While the original answer below is still accurate, it looks like it's the mixture of debug information and optimization which makes a difference here.

From my experiments:

Compiler flags                        Result
/o+ /debug-                           Finalizer runs
/o+ /debug+                           Finalizer runs
/o- /debug-                           Finalizer runs
/o- /debug+                           Finalizer does *not* run


The finalizer is still called on my box, when compiling on the command line with /o+. My guess is that you're running in a debugger - which changes the GC behaviour. Without the debugger, the GC will collect anything that it can prove will never be read. With the debugger, I believe the GC won't collect any objects which still have references on the stack, even if there's no code to read the variables in question.

Now with an object initializer, the compiler code includes an extra reference on the stack. This line:

Zombie z = new Zombie { Name = "Guy" };

is effectively:

Zombie tmp = new Zombe();
tmp.Name = "Guy";
Zombie z = tmp;

The assignment to z is only performed after all the properties have been set.

My guess is that the tmp variable here is keeping the object alive.

这篇关于使用对象初始化复活差异的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆