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

Tagged as

Garbage Collection Notifications in .NET 4.0

, 11 Aug 2010
Rate this:
Please Sign up or sign in to vote.
About Garbage Collection Notifications in .NET 4.0

Memory management is primary for any application. From the very beginning, we have used destructors, or deleted the allocated memory whilst using the other programming languages like C or C++. C# on the other hand being a proprietor of .NET Framework provides us a new feature so that the programmer does not have to bother about the memory deallocation and the framework does it automatically. The basic usage is:

  1. Always leave local variable
  2. Set class variables, events, etc. to null

This leaves us with lots of queries. When does the garbage collection execute? How does it affect the current application? Can I invoke Garbage collection when my system / application is idle?

These questions might come to any developer who has just come to the .NET environment. As for me too, I was doing the application just blindly taking into account that this might be the basic usage of .NET applications, and there might be a hidden hand for me who works for me in background. Until after a few days, I got an alternative to call the Garbage collection using GC.Collect().

But according to the documentation, GC.Collect() is a request. It is not guaranteed that the Collection process will start after calling the method and the memory is reclaimed. So, there is still uncertainty whether the Garbage Collection will actually occur or not.

Why GC.Collect is Discouraged?

GC.Collect actually forces the Garbage collection to invoke its collection process out of its regular cycle. It potentially decreases the performance of the application which calls it. As GC.Collect runs in the thread on which it is called, it starts and quickly finishes the call. In such a phase of GC collection, actually the memory is not being reclaimed, rather it just produces a thorough scan on objects that are out of scope. The memory ultimately freed whenever Full Garbage collection takes place.
For reference, you can read Scotts' blog entry.

What's new in .NET 4.0 (or .NET 3.5 SP1)?

Well, GC has changed a bit with the introduction of .NET 4.0, so that the programmer has better flexibility on how to use GC. One of such changes is the signature of GC.Collect().

Initially, GC.Collect only allowed you to use Optimization call. Now it has 3 overloads:

  • GC.Collect (): Forces an immediate garbage collection for all generations
  • GC.Collect(int): You pass the Generation 0 to a specified generation to collect all generations starting from 0.
  • GC.Collect(int, GCCollectionMode): You can also specify the CollectionMode in addition to it. The CollectionMode can be CollectionMode.Force, CollectionMode.Optimized, and Default which is Forced.

GC.Collect is Forced by default, so once you call it, it will automatically invoke the collection process.
So it's a great relief to all of you, right?

GC Notifications

Another feature that is introduced with GC in .NET 3.5 SP 1 is to produce notifications whenever GC collection is about to begin and GC collection is completed successfully. Say you are between a very resource consuming phase of your application, GC notification will allow you to get notified that GC is approaching, so that you could stop the current process and wait for GC to complete. This makes your application run smoothly. So how can you do this? Let's look at the steps:

  1. Call GC.RegisterForFullGCNotification to allow for notifications when GC is approaching.
  2. Create a new thread from the application and start poll continuously in an infinite loop to methods GC.WaitForFullGCApproach and/or GC.WaitForFullGCComplete methods.
  3. Both the method return GCNotificationStatus.Succeeded when the notification has to be raised.
  4. In Calling thread, use GC.CancelFullGCNorification to unregister the notification process.

Now let's implement the code:

public class MainProgram
{
    public static List<char[]> lst = new List<char[]>();
    public static void Main(string[] args)
    {
        try
        {
            // Register for a notification. 
            GC.RegisterForFullGCNotification(10, 10);

            // Start a thread using WaitForFullGCProc.
            Thread startpolling = new Thread(() =>
            {
                while (true)
                {
                    // Check for a notification of an approaching collection.
                    GCNotificationStatus s = GC.WaitForFullGCApproach(1000);
                    if (s == GCNotificationStatus.Succeeded)
                    {
                        //Call event

                        Console.WriteLine("GC is about to begin");
                        GC.Collect();
                    }
                    else if (s == GCNotificationStatus.Canceled)
                    {
                        // Cancelled the Registration
                    }
                    else if (s == GCNotificationStatus.Timeout)
                    {
                        // Timeout occurred.
                    }

                    // Check for a notification of a completed collection.
                    s = GC.WaitForFullGCComplete(1000);
                    if (s == GCNotificationStatus.Succeeded)
                    {
                        //Call event
                        Console.WriteLine("GC has ended");
                    }
                    else if (s == GCNotificationStatus.Canceled)
                    {
                        //Cancelled the registration
                    }
                    else if (s == GCNotificationStatus.Timeout)
                    {
                        // Timeout occurred
                    }

                    Thread.Sleep(500);
                }                    
            });
            startpolling.Start();

            //Allocate huge memory to apply pressure on GC
            AllocateMemory();
                
            // Unregister the process
            GC.CancelFullGCNotification();

        }
        catch { }
    }

    private static void AllocateMemory()
    {
        while (true)
        {
                
            char[] bbb = new char[1000]; // creates a block of 1000 characters
            lst.Add(bbb);                // Adding to list ensures that the 
					// object doesn't get out of scope   
            int counter = GC.CollectionCount(2);
            Console.WriteLine("GC Collected {0} objects", counter);

        }
    }        
}

Here when the program starts, I have called RegisterForFullGCNotification. This call registers the GC to start notifying using the notifiers. Please note that the call to RegisterForFullGCNotification will fail if a concurrent GC is enabled. You will see "This API is not available when the concurrent GC is enabled." Concurrent GC means the garbage collection will run in separate threads concurrently. If your application has to do some heavy task, leave concurrent GC enabled. This makes the GC run collection without interrupting the application thread. For ASP.NET application, you should disable concurrentGC.

To disable Concurrent GC, add App.config and put:

<configuration>
    <runtime>
      <gcConcurrent enabled="false" />
    </runtime>
</configuration>

After concurrent GC is disabled, you can run the application. After calling RegisterForFullGCNotification, we start a new thread. In the thread, we continuously poll WaitForFullGCApproach which returns GCNotificationStatus.Succeeded whenever the GC is approaching. It is better to call GC.Collect in this situation to ensure that collection starts immediately.

We also poll WaitForFullGCComplete which returns GCNotificationStatus.Succeeded whenever the GC collection is complete.

We use GC.CancelFullGCNotification() to stop using Notification.

From the main thread, we are continuously allocating memory to check when GC collection occurs. The GC.CollectionCount to determine how much GC collection took place at a given instance of time. Use 0 - 2 to check each generation individually.

Download sample application - 30 KB


Please feel free to leave your comments on this new feature.

License

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

Share

About the Author

Abhishek Sur
Architect
India India
Did you like his post?
 
Oh, lets go a bit further to know him better.
Visit his Website : www.abhisheksur.com to know more about Abhishek.
 
Abhishek also authored a book on .NET 4.5 Features and recommends you to read it, you will learn a lot from it.
http://bit.ly/EXPERTCookBook
 
Basically he is from India, who loves to explore the .NET world. He loves to code and in his leisure you always find him talking about technical stuffs.
 
Presently he is working in WPF, a new foundation to UI development, but mostly he likes to work on architecture and business classes. ASP.NET is one of his strength as well.
Have any problem? Write to him in his Forum.
 
You can also mail him directly to abhi2434@yahoo.com
 
Want a Coder like him for your project?
Drop him a mail to contact@abhisheksur.com
 
Visit His Blog

Dotnet Tricks and Tips



Dont forget to vote or share your comments about his Writing
Follow on   Twitter   Google+

Comments and Discussions

 
GeneralMy vote of 5 PinmentorKunalChowdhury11-Aug-10 16:47 
GeneralRe: My vote of 5 PinmvpAbhishek Sur11-Aug-10 23:41 

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 | Mobile
Web02 | 2.8.140826.1 | Last Updated 11 Aug 2010
Article Copyright 2010 by Abhishek Sur
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid