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

GC Algorithm and Story of WeakReference

, 31 Oct 2010 CPOL
Rate this:
Please Sign up or sign in to vote.
WeakReference comes very handy when working with Large objects. In this application, I have demonstrated how you could easily use this class to improve the performance of your application.

Introduction

We all know that .NET objects deallocate memory using Garbage Collection. Garbage collection is a special process that hooks in to the object hierarchy randomly and collects all the objects that are not reachable to the application running. Let us make Garbage collection a bit clear before moving to the alternatives.

GC Algorithm

In .NET, every object is allocated using Managed Heap. We call it managed as every object that is allocated within the .NET environment is in explicit observation of GC. When we start an application, it creates its own address space where the memory used by the application would be stored. The runtime maintains a pointer which points to the base object of the heap. Now as the objects are created, the runtime first checks whether the object can be created within the reserved space, if it can it creates the object and returns the pointer to the location, so that the application can maintain a Strong Reference to the object. I have specifically used the term Strong Reference for the object which is reachable from the application. Eventually the pointer shifts to the next base address space.

reference.JPG

When GC strikes with the assumption that all objects are garbage, it first finds all the Strong References that are global to the application, known as Application Roots and goes on object by object. As it moves from object to object, it creates a Graph of all the objects that it finds from the application Roots, such that every object in the Graph is unique. When this process is finished, the Graph will contain all the objects that are somehow reachable to the application. Now as the GC already identified the objects that are not garbage to the application, it goes on Compaction. It linearly traverses to all the objects and shifts the objects that are reachable to non reachable space which we call as Heap Compaction. As the pointers are moved during the Heap compaction, all the pointers are reevaluated again so that the application roots are pointing to the same reference again.

Is WeakReference an Exception?

On each GC cycle, a large number of objects are collected to release the memory pressure of the application. As I have already stated, it finds all the objects that are somehow reachable to the Application Roots. The references that are not collected during the Garbage Collection are called Strong Reference, as by the definition of Strong Reference, the objects that are reachable to the GC are called Strong Reference objects.

This creates a problem. GC is indeterminate. It randomly starts deallocating memory. So say if one has to work with thousand bytes of data at a time, and after it removes the references of the object it had to rely on the time when GC strikes again and removes the reference. You can use GC.Collect to request the GC to start collecting, but this is also a request.

Now say you have to use the large object once again, and you removed all the references to the object and need to create the object again. Here comes huge memory pressure. So in such a situation, you have:

  1. Already removed all references of the object
  2. Garbage collection didn't strike and removed the address allocated
  3. You need the object again

In such a case, even though the object is still in the application memory area, you still need to create another object. Here comes the use of WeakReference.

Types of WeakReference

WeakReference can be of two types:

  • Short: Short WeakReference loses the reference when the GC is collected. In our case, we have used short WeakReference.
  • Long: Long WeakReference is retained even when the objects Finalize method is called. In this case, the object state cannot be determined. We pass trackResurrection to true in the constructor of WeakReference which defaults false, to track the object even though the Finalize method is called.

A WeakReference object takes the Strong Reference of an object as argument which you can retrieve using Target property. Let us look into the example:

To demonstrate the feature, let's create a class which uses a lot of memory.

 public class SomeBigClass : List<string>
 {
        public SomeBigClass()
        {
            this.LoadBigObject();
        }
        private void LoadBigObject()
        {
            for (int i = 0; i < 100000; i++)
                this.Add(string.Format("String No. {0}", i));
        }       
    } 

Clearly the SomeBigClass is a list of 100000 strings. The code looks very straight forward, as I have just created an alternative to define List<string>. Now let's create another class to show the actual implementation of the WeakReference class.

public class WeakReferenceUsage
    {
        WeakReference weakref = null;

        private SomeBigClass _somebigobject = null;

        public SomeBigClass SomeBigObject
        {
            get
            {
                SomeBigClass sbo = null;
                if (weakref == null)  
               //When it is first time or object weakref is collected.
                {
                    sbo = new SomeBigClass();
                    this.weakref = new WeakReference(sbo);
                    
                    this.OnCallBack("Object created for first time");
                }
                else if (weakref.Target == null) // when target object is collected
                {
                    sbo = new SomeBigClass();
                    weakref.Target = sbo;
                    this.OnCallBack("Object is collected by GC, 
			so new object is created");
                }
                else // when target object is not collected.
                {
                    sbo = weakref.Target as SomeBigClass;
                 this.OnCallBack("Object is not yet collected,
			so reusing the old object");
                }

                this._somebigobject = sbo; //gets you a strong reference
                return this._somebigobject;
            }
            set
            {
                this._somebigobject = null;
            }
        }

        # region GarbageEvent

        public event Action<string> CallBack;

        public void OnCallBack(string info)
        {
            if (this.CallBack != null)
                this.CallBack(info);
        }
        # endregion
    } 

In the above class, we define a reference of WeakReference as weakref, which holds the object of SomeBigClass. Now the property SomeBigClass has little logic defined within it. It uses the existing WeakReference.Target to fetch the existing object. If the Target is null, the object will again be recreated and stored within the WeakReference Target again.

WeakReference serves as an exception to the existing GC algorithm. Even though the object is reachable from the application, it is still left for GC collection. So if GC strikes, it will collect the object of SomeBigClass and the WeakReference.Target will lose the reference.

Demonstration of the Code

To demonstrate the class, let's create a Console application and create the object of WeakReferenceUsage. Let the example class look like:

static void Main(string[] args)
{
      WeakReferenceUsage wru = new WeakReferenceUsage();
      wru.CallBack += new Action<string>(wru_CallBack);
      while (true)
      {
          //Access somebigclass
          foreach (string fetchstring in wru.SomeBigObject)
              Console.WriteLine(fetchstring);
          //fetch complete.
          wru.SomeBigObject = null;
          GC.Collect(); // request to collect garbage.
          ConsoleKeyInfo info = Console.ReadKey();
          if (info.Key == ConsoleKey.Escape)
              break;
      }
}
static void wru_CallBack(string obj)
{
     Console.WriteLine(obj);
     Console.Read();
 } 

Here in the Main method, I have created an object of WeakReferenceUsage, and registered the callback so that whenever we try to retrieve the object, the message will be displayed in the console.

By setting:

wru.SomeBigObject = null;
GC.Collect(); // request to collect garbage. 

It will destroy the strong application reference and hence the object will be exposed for Garbage Collection. The call GC.Collect will request the garbage collection to collect.

Thus on first run, you will see:

weakrefdemo.JPG

The object is created for the first time.

weakrefdemo1.JPG

weakrefdemo2.JPG

After you fetch all the data, you might either receive the second message, saying that the object is not yet collected and the object is fetched from the existing WeakReference, or if you wait for a long time, you might receive the 3rd message which says that the object is collected by GC and object is recreated.

History

  • Initial draft - 31 October 2010

I hope the article will help you to workaround on large objects.

Looking for your feedback.

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 2 Pinmemberring_031-Oct-10 7:44 
GeneralRe: My vote of 2 PinmvpAbhishek Sur31-Oct-10 8:25 

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
Web01 | 2.8.141022.2 | Last Updated 31 Oct 2010
Article Copyright 2010 by Abhishek Sur
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid