Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C# Destructor not working as expected

Please see the code below. I expect it to print either 10 because I have explicitly invoked the garbage collector. But I always get either a 0 or 20 as output. Why is that?

void Main()
{
    Panda[] forest_panda = new Panda[10];
    for(int i=0; i<forest_panda.GetLength(0);i++)
    {
        forest_panda[i]=new Panda("P1");
    }

    for(int i=0; i<forest_panda.GetLength(0);i++)
    {
        forest_panda[i]=new Panda("P1");
    }

    System.GC.Collect();

    Console.WriteLine("Total Pandas created is {0}",Panda.population);          
}

class Panda
{
    public static int population=0;
    public string name;

    public Panda(string name)
    {
        this.name = name;
        population = population + 1;
    }

    ~Panda()
    {
        population = population - 1;
    }   
}

Please note that the class for Main is automatically created by LINQPad (the editor that comes with the "C# 4.0 in a Nutshell" book). I am new to C#.

like image 822
Manoj Avatar asked Aug 17 '10 05:08

Manoj


People also ask

What C is used for?

C programming language is a machine-independent programming language that is mainly used to create many types of applications and operating systems such as Windows, and other complicated programs such as the Oracle database, Git, Python interpreter, and games and is considered a programming foundation in the process of ...

What is the full name of C?

In the real sense it has no meaning or full form. It was developed by Dennis Ritchie and Ken Thompson at AT&T bell Lab. First, they used to call it as B language then later they made some improvement into it and renamed it as C and its superscript as C++ which was invented by Dr.

What is C in C language?

What is C? C is a general-purpose programming language created by Dennis Ritchie at the Bell Laboratories in 1972. It is a very popular language, despite being old. C is strongly associated with UNIX, as it was developed to write the UNIX operating system.

Is C language easy?

C is a general-purpose language that most programmers learn before moving on to more complex languages. From Unix and Windows to Tic Tac Toe and Photoshop, several of the most commonly used applications today have been built on C. It is easy to learn because: A simple syntax with only 32 keywords.


2 Answers

You have not run an explict garbage collection. From the docs of GC.Collect():

Use this method to attempt to reclaim all memory that is inaccessible. However, the Collect method does not guarantee that all inaccessible memory is reclaimed.

All objects, regardless of how long they have been in memory, are considered for collection; however, objects that are referenced in managed code are not collected. Use this method to force the system to attempt to reclaim the maximum amount of available memory.

The garabage collector is highly optimized and "decides" all by himself when he actually does the garbage collection and then call the finalizers. Additionally it is all done asynchronously. That is also why Finalizers are called non-deterministic cleanup. You never now when cleanup happens.

You have two options now. You can either call GC.WaitForPendingFinalizers() wich will halt the current thread until the all finalizable objects have been finalized. Or call this new overload: System.GC.Collect(int generation, System.GCCollectionMode mode) with GCCollectionMode.Forced It was introduced in .NET 3.5.

Just keep in mind that usually it is not necessary and more importantly: a bad idea to call the garbage collector manually. Also implementing the finalizer is only needed in rare occasions. Calling the garbage collector will slow down the runtime. Implementing finalizers will slow down the runtime additionally. The garabge collector puts all objects that implement the finalizer into the finalization queue when they are ready to be garabge collected. Processing this queue is expensive. To make things worse, when the finalizer is run, it is not guaranteed that the members you are trying to access there are still alive. It is very well possible they have already been grabage collected. That's why you should use the finalizer only when you have unmanaged resources that need to be cleaned up.

All this is definately not needed in your example. What you acutally want is IDisposable for deterministic cleanup.

like image 156
bitbonk Avatar answered Nov 02 '22 22:11

bitbonk


There are a couple of things to notice here:

First of all the GC behaves differently between release and debug builds. Generally, in release mode objects can be reclaimed sooner than in debug mode.

As Tim points out calling GC.Collect doesn't call finalizers. If you want to wait for finalizers to run call GC.WaitForPendingFinalizers as well.

Finalizers are run by a dedicated thread, so you're actually modifying state from two different threads without any synchronization. While this may not be a problem in this particular case, doing so is not a good idea. But before you go and add synchronization to your finalizer, please keep in mind that a deadlocked finalizer means that no more finalizers will run and thus the memory for those objects will not be reclaimed.

like image 21
Brian Rasmussen Avatar answered Nov 02 '22 23:11

Brian Rasmussen