I'm trying to learn how finalization and destructor works in C#, I tried to run the code in the System.Object.Finalize
example(code copy-pasted, no changes made), but the output is not the same as expected, it shows that the destructor is never called.
The code is:
using System;
using System.Diagnostics;
public class ExampleClass
{
Stopwatch sw;
public ExampleClass()
{
sw = Stopwatch.StartNew();
Console.WriteLine("Instantiated object");
}
public void ShowDuration()
{
Console.WriteLine("This instance of {0} has been in existence for {1}",
this, sw.Elapsed);
}
~ExampleClass()
{
Console.WriteLine("Finalizing object");
sw.Stop();
Console.WriteLine("This instance of {0} has been in existence for {1}",
this, sw.Elapsed);
}
}
public class Demo
{
public static void Main()
{
ExampleClass ex = new ExampleClass();
ex.ShowDuration();
}
}
Update:
When I use visual studio and .net framework 4.5, the code works as expected: Output same as example:
The example displays output like the following: Instantiated object This instance of ExampleClass has been in existence for 00:00:00.0011060 Finalizing object This instance of ExampleClass has been in existence for 00:00:00.0036294
When I use dotnet core app, the code does not work: The actual output is:
PS C:\ws\test> dotnet run Instantiated object This instance of ExampleClass has been in existence for 00:00:00.0056874
So why this is different in .NET Core?
The C# compiler does not allow you to override the Finalize method. Instead, you provide a finalizer by implementing a destructor for your class. A C# destructor automatically calls the destructor of its base class. Visual C++ also provides its own syntax for implementing the Finalize method.
The destructor will only get called when the garbage collector decides to collect your instance. The garbage collector runs infrequently, typically only when it detects that there is memory pressure. The garbage collector collects ONLY orphaned collections.
Finalize method also called destructor to the class. Finalize method can not be called explicitly in the code. Only Garbage collector can call the the Finalize when object become inaccessible.
The Finalize method is used to perform cleanup operations on unmanaged resources held by the current object before the object is destroyed. The method is protected and therefore is accessible only through this class or through a derived class.
Putting together information from comments by Peter Duniho and Henk Holterman and expanding on it further:
This behavior is in violation of the C# 5.0 spec from Microsoft and the current draft of the C# 6.0 spec from Microsoft, which say:
Prior to an application's termination, destructors for all of its objects that have not yet been garbage collected are called, unless such cleanup has been suppressed (by a call to the library method
GC.SuppressFinalize
, for example).
But it's not a bug, .Net Core intentionally diverged from the .Net Framework behavior, as explained in a corefx issue:
Currently, a best-effort attempt is made to run finalizers for all finalizable objects during shutdown, including reachable objects. Running finalizers for reachable objects is not reliable, as the objects are in an undefined state.
…
Proposal
Don't run finalizers on shutdown (for reachable or unreachable objects)
…
Under this proposal, it is not guaranteed that all finalizable objects will be finalized before shutdown.
Presumably due to this, the C# 5.0 spec from ECMA weakened this requirement, so .Net Core does not violate this version of the spec:
Prior to an application’s termination, an implementation should make every reasonable effort to call finalizers (§15.13) for all of its objects that have not yet been garbage collected, unless such cleanup has been suppressed (by a call to the library method
GC.SuppressFinalize
, for example). The implementation should document any conditions under which this behavior cannot be guaranteed.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With