Click here to Skip to main content
Click here to Skip to main content

Non-Deterministic Destructors - What Are They?

, 31 Jul 2007 CPOL
Rate this:
Please Sign up or sign in to vote.
An article on non-deterministic destructors in C#

Introduction

This article provides an introduction to destructors in C# and reveals the non-deterministic destructor problem.

It also analyzes the IDisposable, garbage collection, using statement, etc.

Destructor

The destructor is a special purpose method in a class like a constructor. The constructor is called by the runtime after creating an instance. It is meant for initialization purposes. Like that, a destructor is called by the runtime before destroying an instance. It is meant for finalization operations.

A destructor is declared like a constructor with a prefix tilde(~) in C#. A destructor do not have access modifiers like public, private, etc.

public class Shape
{
    ~Shape() // Destructor
    {
    }
}

In C#, the .NET runtime automatically destroys any class instances that are no longer in reference. It does this during the process of garbage collection.

Using of destructors will make the application slow in performance.

Finalizers

It is important to note that the destructors are also called Finalizers because the compiler converts a C# destructor into a method named Finalize() in the Intermediate Language (IL). The code in the destructor will be wrapped in a try..finally block inside the Finalize() method.

Screenshot - Finalizers2.png

Garbage Collection

This is the process of freeing up of unused memory of objects periodically. The .NET runtime does the process of garbage collection on the following conditions:

  • When there is shortage of memory
  • Developer invoked the GC.Collect() method

The garbage collection helps the developer to free up object instances.

But remember, garbage collection only destroys the managed resources, i.e. resources created inside the managed memory.

What is the Need of Destructors?

Since the runtime is managing the destruction of all objects, a question may arise: Why do we need destructors?

Answer: To destroy unmanaged resources.

The unmanaged resources are those created outside the managed environment. They may include file handles, network connections, etc. These resources created should be destroyed by the class itself, because the runtime is not able to destroy them.

Screenshot - Memory.png

Therefore, we use destructors to free up the unmanaged resources. This will ensure that all the unmanaged resources created by the class will be freed in the destructor.

E.g.: Let Channel be a class using unmanaged resources having a constructor and a destructor.

public class Channel
{
    public Channel()
    {
        // Create unmanaged resource
        // Lock("c:\\file.log");
    }

    ~Channel()
    {
        // Destroy unmanaged resource
        // Unlock("c:\\file.log");
    }
}

The Channel class locks a file "c:\file.log" in the constructor and unlocks it in the destructor.

Here arises a problem that we cannot predict when the destructor is called. So the file remains locked until the garbage collection, even if the object instance is out of any reference.

For the above problem, we need some method to free the unmanaged resource. In .NET, there is an interface named IDisposable for the purpose.

IDisposable

The IDisposable interface contains a method Dispose() which should be implemented by the class. So we can move freeing up of unmanaged resources to this Dispose() method.

Again there is a problem, that a typical .NET developer not calling the Dispose() method after the usage of class instance. In that case, we need the call to free unmanaged resources both in the destructor and in the Dispose() method.

We can also use a Close() method instead of implementing the IDisposable interface. But, enabling the IDisposable makes our class usable in the using {} statement of C#.

The using statement will automatically call the Dispose() method after exiting the scope of using. (Please refer to the sample code.)

public class Channel : IDisposable
{
    public Channel()
    {
        // Create unmanaged resource
        Lock("c:\\file.log");   
    }
    ~Channel()
    {
        // Destroy unmanaged resource
        Unlock("c:\\file.log");
    }
    void IDisposable.Dispose()
    {
        Unlock("c:\\file.log");
    }
    public void Lock(string file) { } 
    public void Unlock(string file) { }
}

At first look, the above code solves all the problems.

But, it creates a new problem due to the non-deterministic destructors of C#.

Non-Deterministic Destructors

In C#, we do not know when the destructor is executed. It is called only during the garbage collection process and we do not know when it actually happens. This state is called non-deterministic destructors or InDeterministic destructors.

The following figure illustrates the problem. Our 'Channel' class is using some unmanaged resources and freeing them in the Dispose() method and also in the destructor.

There are two cases when the Channel class is used:

  1. A developer creates an instance and exits without calling Dispose()
  2. A developer creates an instance and calls Dispose()

Screenshot - Scenarios.png

Solution using GC.SuppressFinalize(this)

We can instruct the garbage collector not to call the destructor by using the GC.SuppressFinalize(this) method. So, using this in the Dispose() method after freeing up unmanaged resources will solve the non-deterministic destructor problem.

The solution is given below.

Here, the Channel class has freed up code both in the destructor and in the Dispose() method. And if the developer calls the Dispose() method, the unmanaged resources will be freed and the destructor will be disabled by using GC.SuppressFinalize(this);.

If the developer does not call the Dispose() method, the unmanaged resources are freed up in the destructor by the garbage collector. The figure below illustrates the solution:

Screenshot - Solution.png

Note: The Dispose() method is used to free up the unmanaged resources, and calling Dispose() will not free up the instance. It just executes whatever statements are written in it.

Using the Code

The code along with this article demonstrates the case of using/not using Dispose(), and also the initiating of the GarbageCollection process using GC.Collect(). Please analyze the Channel class to see the details involved.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Jean Paul V.A
Architect
United States United States
Jean Paul is a Microsoft MVP and Architect with 12+ years of experience. He is very much passionate in programming and his core skills are SharePoint, ASP.NET & C#.
 
In the academic side he do hold a BS in Computer Science & MBA. In the certification side he holds MCPD & MCTS spanning from .Net Fundamentals to SQL Server.
 
Most of the free time he will be doing technical activities like researching solutions, writing articles, resolving forum problems etc. He believes quality & satisfaction goes hand in hand.
 
You can find some of his work over here. He blogs at http://jeanpaulva.com
Follow on   Twitter

Comments and Discussions

 
QuestionEasy to read, and well explained PinmemberJason Wu28-May-13 12:05 
AnswerRe: Easy to read, and well explained PinmvpJean Paul V.A28-May-13 12:21 
GeneralNice article PinmemberBert delaVega31-Jul-07 7:28 
GeneralRe: Nice article PinmemberJean.Paul31-Jul-07 23:58 
General'destructor' is missleading Pinmemberdmihailescu24-Jul-07 9:54 
You better use the world finalizer than destructor to avoid confusion.
GeneralRe: 'destructor' is missleading PinmemberRexNebular24-Jul-07 11:28 
GeneralRe: 'destructor' is missleading Pinmembertaras_b24-Jul-07 14:21 
GeneralRe: 'destructor' is missleading [modified] PinmemberRexNebular24-Jul-07 22:00 
GeneralDispose throwing error PinmemberRexNebular24-Jul-07 5:12 
GeneralRe: Dispose throwing error Pinmemberwkempf24-Jul-07 5:26 
GeneralRe: Dispose throwing error PinmemberRexNebular24-Jul-07 5:51 
GeneralRe: Dispose throwing error Pinmemberwkempf24-Jul-07 5:54 
GeneralRe: Dispose throwing error PinmemberRexNebular24-Jul-07 6:06 
GeneralRe: Dispose throwing error Pinmemberwkempf24-Jul-07 6:17 
GeneralRe: Dispose throwing error PinmemberRexNebular24-Jul-07 6:25 
GeneralRe: Dispose throwing error Pinmemberwkempf24-Jul-07 6:35 
GeneralRe: Dispose throwing error PinmemberMember 308579014-Jan-09 23:37 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web04 | 2.8.141223.1 | Last Updated 31 Jul 2007
Article Copyright 2007 by Jean Paul V.A
Everything else Copyright © CodeProject, 1999-2014
Layout: fixed | fluid