codeflood logo

Warning: Memory leaks ahead

Hang on, memory leaks? But this is .net where memory leaks are a thing of the past. If you've never done C or C++ before, then you've probably never had the enjoyment of searching through your code looking for memory leaks. A memory leak is memory an application allocates, but doesn't deallocate when it's done with it. .net solved this issue by not letting the developer manage the memory of the application. Instead, .net uses a garbage collector which cleans up unreachable memory so the developer doesn't have to worry about freeing the memory from dead objects anymore.

The way in which the garbage collector works out if an object is still being used is by walking through each object in memory to see if other objects hold a reference to it. If a reference exists then the object is reachable and is not destroyed.

So if the garbage collector is taking care of cleaning up old objects, how can I have a memory leak in .net? Simply if I hold a reference to an object I assumed would be destroyed. This happens when using events. An event subscriber is a reference and this reference will prevent a subscriber from being collected.

Allow me illustrate with some code.

using System;
namespace EventLeak
{
  class Program
  {
    static Broadcast m_broadcast = null;

    static void Main(string[] args)
    {
      Setup();
      m_broadcast.CallBing();
      Console.Read();
    }

    public static void Setup()
    {
      m_broadcast = new Broadcast();
      Subscriber s = new Subscriber(m_broadcast);
    }
  }

  class Broadcast
  {
    public event EventHandler Bing;

    public void CallBing()
    {
      if (Bing != null)
        Bing.Invoke(this, new EventArgs());
    }
  }

  class Subscriber
  {
    public Subscriber(Broadcast b)
    {
      b.Bing += new EventHandler(Handler);
    }

    public void Handler(object sender, EventArgs args)
    {
        Console.WriteLine(this.GetHashCode().ToString() +
          " Handled object");
    }
  }
}

In the above code sample, the subscriber is created as a local variable in the Setup method. Once we leave this method the object goes out of scope and if not for the event subscription, the subscriber object would be eligible for garbage collection. But the subscription keeps the object alive. If you execute the above program you will see the subscriber outputs to the console indicating it's not dead.

I have in the past relied on this behavior. It allows me to create objects and hook them into events, but not have to worry about keeping them alive. But a problem arises if you assume the object is going to be destroyed when you leave it's scope. This is where the memory leak is. We assume an object will be destroyed, but it isn't.

In 2005, a team form Princeton University entered into the DARPA grand challenge in which teams had to design and create an autonomous car to drive around a predefined course. This team chose .net as their platform. They performed very well and made it though to the national finals. During this final race, all was going well, until the car ran out of memory. For each obstacle the sensors detected, an object was created and hooked into events of another part of the system. The team assumed the objects were being destroyed when they left scope, but because they were subscribers to an event, they didn't and so a memory leak occurred. You can read all about it (and their plug for ants profiler) at http://www.codeproject.com/KB/showcase/IfOnlyWedUsedANTSProfiler.aspx.

And Sitecore is no exception with it's event pool. In Sitecore, we can programmatically subscribe to events from the event pool using the Subscribe method of the Event class.

Sitecore.Events.Event.Subscribe("item:created", new EventHandler(Handler));

This is the same as the more familiar += event subscription notation.

So how do I have my objects die and not live forever? I need to unsubscribe from the event. In standard .net I need to use -= to remove the handler, and for the Sitecore event pool I need to use the Unsubscribe method of the Event class.

Button.Click -= new EventHandler(Handler);
Sitecore.Events.Event.Unsubscribe("item:created", new EventHandler(Handler));

When to unsubscribe will depend on exactly what you are doing, but most often the perfect place to unsubscribe will be when we decide the object is no longer needed. For this we need to implement the IDisposable interface and remove the subscription in the Dispose method.

class Subscriber : IDisposable
{
  Broadcast m_broadcast = null;

  public Subscriber(Broadcast b)
  {
    m_broadcast = b;
    m_broadcast.Bing += new EventHandler(Handler);
  }

  public void Dispose()
  {
    m_broadcast.Bing -= new EventHandler(Handler);
  }

  public void Handler(object sender, EventArgs args)
  {
    Console.WriteLine(this.GetHashCode().ToString() +
      " Handled object");
  }
}

So the bottom line is, if I subscribe to an event and the subscriber doesn't live as long as the application, unsubscribe when the object is disposed.

Comments

I'm not sure if you're aware or not but this is a feature within JavaScript, called Closure ;)

This is one of the most interesting articles I have read. Memory leaks can be a huge issue in Sitecore, because of the massive use of caching. Great work.

RaiulBaztepo

Hello! Very Interesting post! Thank you for such interesting resource! PS: Sorry for my bad english, I'v just started to learn this language ;) See you! Your, Raiul Baztepo

Leave a comment

All fields are required.