Labels

Wednesday, August 6, 2008

Event Wiring - Can lead to Memory Leaks

Hi,

Here I’ll be covering the how the Event Wiring can lead to a big memory leak. I’m using ANTS Profiler to come up to this case study.

I have never noticed that the Event Wiring can lead to a big Memory leak problem.

Notice the below code – Leading to lot of Memory leak

public delegate void MyDelegate();

public partial class TemplatePage : System.Web.UI.Page

{

protected void Page_Load(object sender, EventArgs e)

{

MyEventClass.MyEvent += new MyDelegate(MyEventClass_MyEvent); // Notice the code is not kept in if(!IsPostBack)

}

void MyEventClass_MyEvent()

{}

}

public class MyEventClass

{

public static event MyDelegate MyEvent;

}

In order to test the code, run ANTS Profiler and refresh the web page 30 times. Now if you see the report, you’ll find there are MyDelegate object which are still live.

Approach – 1

In order to find the root cause of this memory leak, make a small change in the MyEventClass as below.

protected void Page_Load(object sender, EventArgs e)

{

MyEventClass ev = new MyEventClass();

ev.MyEvent += new MyDelegate(MyEventClass_MyEvent);

}

public class MyEventClass

{

public event MyDelegate MyEvent; // Static is removed

}

In order to test the code, run ANTS Profiler and refresh the web page 30 times. Now if you see the report, you’ll find there are no MyDelegate object which are still live.

What is the solution -

- The answer to this particular question is that the event decalred in MyEventClass is static.

- Thus event bidning in Page_Load will survive as long as the web application process continues to run.

- The net effect is that the MyStaticClass is having a new EventHandler i.e MyDelegate attached at every page load.

- The solution is to create MyEvent as a public class, rather than static. Thus new MyStaticClass will be created at every page load, and disposed of when the page has finished loading.

Approach – 2

- There are places where you might not be in the situation to change the Event class code as we did above. For e.g. for the system defined events there is very less provision for the code change.

- For e.g

SiteMap.SiteMapResolve += new SiteMapResolveEventHandler(SiteMapHandler.SiteMap_SiteMapResolve);

- In such cases best is to avoid the event binding multiple times, and make it just once.

To do this it can be done in various ways. For e.g

- Using !IsPostBack

- Session_Start in Global.asax – In this case you need to define a Static method in some class which will work as the Event Handler

protected void Page_Load(object sender, EventArgs e)

{

if (!IsPostBack)

{

MyEventClass.MyEvent += new MyDelegate(MyEventClass_MyEvent);

}

}

void Session_Start(object sender, EventArgs e)

{

SiteMap.SiteMapResolve += new SiteMapResolveEventHandler(MyClass.SiteMap_SiteMapResolve);

}

In order to test the code, run ANTS Profiler and refresh the web page 30 times. Now if you see the report, you’ll find there are no MyDelegate object which are still live.

One more advantage over the first solution is even it saved multiple object creation and hence the GC cycles.

Reference - http://www.red-gate.com/Products/ANTS_Profiler/technical_papers/finding_memory_leaks.htm

Thanks & Regards,

Arun Manglick || Senior Tech Lead

No comments:

Post a Comment