Here is example program that exhibits surprising finalization behavior:
class Something
{
public void DoSomething()
{
Console.WriteLine("Doing something");
}
~Something()
{
Console.WriteLine("Called finalizer");
}
}
namespace TestGC
{
class Program
{
static void Main(string[] args)
{
var s = new Something();
s.DoSomething();
GC.Collect();
//GC.WaitForPendingFinalizers();
s.DoSomething();
Console.ReadKey();
}
}
}
If I run the program, what gets printed is:
Doing something
Doing something
Called finalizer
This appears as expected. Because there is a reference to s after the call to GC.Collect()
, s is not a garbage.
Now remove comments from the line //GC.WaitForPendingFinalizers();
build and run the program again.
I would expect nothing to change in the output. This because I read that if object is found to be a garbage and it has a finalizer, it will be put on finalizer queue. Since object is not a garbage, then is seems logical that it should not be put on finalizer queue. Thus the line commented out should do nothing.
However, the output of the program is:
Doing something
Called finalizer
Doing something
Can somebody help my understanding of why finalizer gets called?
I can't reproduce the problem on my laptop, but your
DoSomething
method doesn't use any fields within the object. That means that the object can be finalized even whileDoSomething
is running.If you change your code to:
... then I suspect you will always see
DoingSomething
printed twice before "Called finalizer" - although the final "x = 12" may be printed after "Called finalizer".Basically, finalization can be somewhat surprising - I very rarely find myself using it, and would encourage you to avoid finalizers wherever possible.