Saturday, February 4, 2012

Optimizing INPC Objects against memory leaks using WeakEvents

Working with WPF has always been a fun. Dealing with animation and richness in UI to its optimum level often gives you an edge to present something to your client and to ensure that your client shouts with a "WOW!". The Wow factor of applications can give you high rank in the first place, but increases expectation from the software. It is practically very hard to maintain with this expectation as time progresses. The survival of the fittest chooses one which best suits to the problem.

One of the major problems that developers face today is the memory leaks in an applications. Often the software that is built looks great but does not follow basic guidelines to ensure that the application is not memory hungry or even there are no existing memory leaks.

Note : By memory leak we mean, some portion of memory is not reclaimed by the garbage collector even though the object is not in use. 

By this way, the memory usage of the application increases at a certain extent and finally crashes with the OutOfMemoryException. To detect a memory leak there exists a large number of tools of which some are free while others are used as commercial purposes. Most of these problems can be fixed by either using Disposable pattern ( IDisposable interface) or manually de - referencing each and every object that are not in use. Sometimes, this can be also done in destructor / finalizers in .net too (but remember using destructors lose GC cycle).



GC algorithm actually tries to find all reachable objects in the entire heap and creates a map. It then puts the reachable objects one by one into the heap releasing memory of all unreachable objects. This is called Heap Compaction. By reachable objects we mean those objects to which the application still has strong reference, and the items which can be called in future. Thus it is important to release any strong reference of a memory when it is not in use, so that GC can collect it.

Even though Garbage Collector separates all the reachable objects with non-reachables, there is one exception to this. .NET framework exposes WeakReference as a special type in the system, which can hold objects that are reachable but still it will be collected by the garbage collector. You can look into it in detail in my post : Garbage Collection Algorithm with the use of WeakReference

The Problem

Now coming back to the application, sometimes it is even difficult to identify a memory leak when it exists inside of its framework. One of such scenario is when a large portion of memory is held by the EventHandler where the source has an EventHandler which is connected with a strong reference of the target which has the event. Let me explain it more :
Object A holding strong reference of Object B through the use of EventHandler
In the above figure, let say Object A is an object that exposes one Event. Suppose Object A is an INPC container and exposes PropertyChanged Event from it. Object B on the other hand consumes Object A and adds an EventHandler inside B. Now it invokes statement to add this handler to the Object A using the code below :
A a1 = new A();
a1.PropertyChanged += new PropertyChangedEventHandler(this.A_PropertyChanged);

So now object A can call A_PropertyChanged event handler defined inside Object B directly.
At a certain point, lets say Object A is no longer in use and is de-referenced from B by doing :

a1 = null;

Here the de-referencing works good, but you are missing the fact that a1 still holds reference of B through the Event PropertyChanged, and will not be GCed until B is de-referenced as well. Here is the problem of memory leak. If B is a Static object and creates lots of A throughout the program, this problem can really leak lots of memory and eventually can load the process to crash.

The Solution

To deal with such a problem, we need a Co-ordinator for the Event such that the event raised by the object does not go directly to the Object B, rather it calls an intermediate listener which routes the event to the handler of Object B.
The Object A is not communicating directly with Object B, rather it connects with a WeakListener which exposes one WeakReference object to hold B

In the above figure, we can see, the Listener co-ordinates the event with the EventHandler thus de-referencing Object A and Listener from Object B will remove all the references from it. Lets implement this approach using code.

interface IPropertyChanged
    {
        void OnPropertyChanged(object sender, PropertyChangedEventArgs e);
    }

    public class WeakEventListener : IDisposable
    {
        readonly object locker = new object();
        WeakReference weakListener;
        INotifyPropertyChanged target;
        IPropertyChanged source;

        public WeakEventListener(IPropertyChanged source, INotifyPropertyChanged target)
        {
            this.source = source;
            this.target = target;
            if (this.target != null)
                this.target.PropertyChanged += new PropertyChangedEventHandler(target_PropertyChanged);
            this.weakListener = new WeakReference(source);
        }

        void target_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            object source = null;
            lock (locker)
            {
                if (weakListener != null)
                {
                    source = weakListener.Target;
                }
                if (source == null)
                {
                    ReleaseListener();
                    return;
                }
            }
            IPropertyChanged notifier = source as IPropertyChanged;
            notifier.OnPropertyChanged(sender, e);

        }

        private void ReleaseListener()
        {
            if (target != null)
            {
                target.PropertyChanged -= new PropertyChangedEventHandler(target_PropertyChanged);
                target = null;
                weakListener = null;
            }
        }
        #region IDisposable Members

        public void Dispose()
        {
            lock (locker)
            {
                this.ReleaseListener();
            }
        }

        #endregion
    }
So here I have implemented one dummy implementation of WeakEventListener. Here the IPropertyChanged  interface is used to reference the object inside the Listener for simplicity.

In the above implementation, you can see, I have used two object. Preferably consider object A in figure with INotifyPropertyChanged object target and IPropertyChanged as object B such that object B creates reference to both INotifyPropertyChanged as well as WeakEventListener. Now if B is derived from interface IPropertyChanged and define the eventhandler inside it, the WeakEventListener can invoke it without holding a strong reference of it.

public class A : INotifyPropertyChanged
{
    string myProperty;
    public string MyProperty
    {
        get { return myProperty; }
        set
        {
            this.myProperty = value;
            if (this.PropertyChanged != null)
                this.PropertyChanged(this, new PropertyChangedEventArgs("MyProperty"));
        }
    }

    #region INotifyPropertyChanged Members

    public event PropertyChangedEventHandler PropertyChanged;

    #endregion
}

public class B : IPropertyChanged
{
    A a1;
    WeakEventListener wlistener;

    public B(A a1)
    {
        this.a1 = a1;
        wlistener = new WeakEventListener(this, a1);
    }

    #region IPropertyChanged Members

    public void OnPropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        MessageBox.Show(string.Format("Property {0}, has been changed", e.PropertyName));
    }

    #endregion


    public void ReleaseA()
    {
        if (this.wlistener != null)
            this.wlistener.Dispose();
        this.wlistener = null;
        this.a1 = null;
    }

}

Now here class A implements INotifyPropertyChanged and invokes it when any of its property is changed. Class B, on the other hand implements IPropertyChanged and provides a eventhandler of PropertyChanged. But as it is using WeakEventListener you can call ReleaseA to release any strong reference of a1 from it and also dispose the listener object. Therefore you can keep on using the object B irrespective of any memory leak been created.

Alternatives inside Framework

WPF has a framework alternative to do the same thing. A number of class are available on the framework which help in implementing the same thing. Lets see how to do this using framework interfaces :

1. Create a class and derive it from WeakEventManager.
2. Implement IWeakEventListener interface to define listener.
3. Use AddListener and RemoveListener to add and remove the objects.

Lets see how I implement the same thing.

class A : INotifyPropertyChanged
{
       
    string myProperty;
    public string MyProperty
    {
        get { return myProperty; }
        set
        {
            this.myProperty = value;
            if (this.PropertyChanged != null)
                this.PropertyChanged(this, new PropertyChangedEventArgs("MyProperty"));
        }
    }
    //code to raise the event
    public event PropertyChangedEventHandler PropertyChanged;
}
class B : IWeakEventListener
{
    A a1;

    public B(A a1)
    {
        this.a1 = a1;
        PropertyChangedEventManager.AddListener(a1, this, "MyProperty");
            
    }
    public bool ReceiveWeakEvent(Type managerType, object sender, EventArgs e)
    {
        PropertyChangedEventArgs pe = e as PropertyChangedEventArgs;

        MessageBox.Show(string.Format("Property {0}, has been changed", pe.PropertyName));

        return true;
    }
    public void ReleaseA()
    {
        PropertyChangedEventManager.RemoveListener(this.a1, this, "MyProperty");
        this.a1 = null;
    }

}

Here the PropertyChangedEventManager is a special class derived from Dispatcher object deals with INPC objects by holding a collection of all those INPC in the whole process and calling appropriate objects when event is raised. Thus ReceiveWeakEvent will be called, just like what we did earlier in B when A raises the event provided you implement IWeakEventListener interface on it.

The ReleaseA is used to release the object A from memory without any strong reference been held.

There is also a CollectionChangedEventManager to deal with ObservableCollection events or even you can build your own by deriving from WeakEventManager.

I hope the post will help you. Please let me know your thoughts.

Thanks for reading.

No comments:

Post a Comment

Please make sure that the question you ask is somehow related to the post you choose. Otherwise you post your general question in Forum section.

Author's new book

Abhishek authored one of the best selling book of .NET. It covers ASP.NET, WPF, Windows 8, Threading, Memory Management, Internals, Visual Studio, HTML5, JQuery and many more...
Grab it now !!!