Resurrection difference when using Object Initializer

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, as a rule, this demo works fine, but today I tried to use the same code with the object initializer instead of just assigning a property (Name in this case). I noticed that there is a difference. Namely, that the finalizer is never called, even when I try my best to make the garbage collector work.

Can someone explain the difference, or did I find a bug in the C # compiler?

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

Thank.

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); } } } } 
+5
garbage-collection c # finalizer
Mar 17 2018-12-17T00:
source share
2 answers

EDIT: Although the original answer below is still accurate, it looks like it's a mixture of debugging and optimization information that matters 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 being called in my field when compiling on the command line using /o+ . I assume that you are working in a debugger that changes the behavior of the GC. Without a debugger, GC collects everything it can prove that it will never be read. With the debugger, I believe that the GC will not collect any objects that still have stack references, even if there is no code to read the variables in question.

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

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

effective:

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

Assignment z is performed only after all properties have been set.

I assume that the tmp variable here supports saving the object.

+16
Mar 17 '12 at 20:10
source share
β€” -

If you need objects that don't die, you really don't need to bother with finalizers. Just create a closed static list of all instances and add objects to this list as they are created:

 class Immortal { static List<Immortal> _immortals = new List<Immortal>(); public Immortal() { _immortals.Add(this); } } 
+1
Mar 17 '12 at 20:07
source share



All Articles