Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C# not releasing memory after task complete

The following code is a simplified example of an issue I am seeing. This application consumes approx 4GB of memory before throwing an exception as the dictionary is too big.

 class Program
 {
    static void Main(string[] args)
    {
        Program program = new Program();

        while(true)
        {
            program.Method();
            Console.ReadLine();
        }
    }

    public void Method()
    {
        WasteOfMemory memory = new WasteOfMemory();
        Task tast = new Task(memory.WasteMemory);
        tast.Start();
    }


}

public class WasteOfMemory
{
     public void WasteMemory()
     {
         Dictionary<string, string> aMassiveList = new Dictionary<string, string>();

         try
         {
             long i = 0;
             while (true)
             {
                 aMassiveList.Add(i.ToString(), "I am a line of text designed to waste space.... I am exceptionally useful........");
                 i++;
             }

         }
         catch(Exception e)
         {
             Console.WriteLine("I have broken myself");
         }
     }
}

This is all as expected, although what we cannot currently work out is when this memory should be released from the CLR.

We have let the task complete and then simulated a memory overload situation, but the memory consumed by the dictionary is not released. As the OS is running out of memory, is it not putting pressure on the CLR to release the memory?

However and even more confusing, if we wait until the task has completed, then hit enter to run the task again the memory is released, so obviously the previous dictionary has been garbage collected (hasn't it?).

So, why is the memory not being released? And how can we get the CLR to release the memory?

Any explanations or solutions would be greatly appreciated.

EDIT: Following replies, particularly Beska's, it is obvious my description of the issue is not the the clearest, so I will try to clarify.

The code may not be the best example, sorry! It was a quick crude piece of code to try to replicate the issue.

The dictionary is used here to replicate the fact we have a large custom data object, which fills a large chunk of our memory and it is not then released after the task has completed.

In the example, the dictionary fills up to the limit of the dictionary and then throws an exception, it does NOT keep filling forever! This is well before our memory is full, and it does not cause an OutOfMemoryException. Hence the result is a large object in memory, and then the task completes.

At this point we would expect the dictionary to be out of scope, as both the task and the method 'Method' have completed. Hence, we would expect the dictionary to be garbage collected and the memory reclaimed. In reality, the memory is not freed until 'Method' is called again, creating a new WasteOfMemory instance and starting a new task.

Hopefully that will clarify the issue a bit

like image 418
DanGordon Avatar asked Jul 03 '12 17:07

DanGordon


1 Answers

The garbage collector only frees locations in memory that are no longer in use that are objects which have no pointer pointing to them.

(1) your program runs infinitely without termination and

(2) you never change the pointer to your dictionary, so the GC has certainly no reason to touch the dictionary.

So for me your program is doing exactly what it is supposed to do.

like image 189
marc wellman Avatar answered Sep 27 '22 17:09

marc wellman