Am I getting obsessed with memory leaks?  Give me a non-leaking browser and I'll cut it out .

Yesterday I was hunting for a hard-to-find memory leak with r.a.d.treeview.  Our component cleans up its DOM element references and DOM event handlers when it is being destroyed.  Control destruction and resource disposal occurs on two occasions:  when the page unloads and when the control is updated by an AJAX call (r.a.d.callback, Atlas, etc -- the mechanism is framework-agnostic).  Now the treeview, being a good citizen, follows the leak prevention pattern of keeping references to DOM elements to a minimum.  Most of the time it keeps an ID and gets the element, manipulates it, and releases the reference on the double.  Here is a rough approximation of RadTreeView's client-side Dispose method:

============= the leaky disposal ===================

RadTreeView.prototype.Dispose = function()
{
    var rootElement = document.getElementById(this.RootElementID);
    //clean up rootElement event handlers here
}

==============================================

This thing works really well in a non-AJAX scenario.  The treeview gets its root element and unhooks the event handlers whenever the page gets unloaded.  Now, AJAX updates turn this whole thing around.  AJAX frameworks do two things: update the rendered HTML on the page and execute all the client scripts, rendered by the updated controls.  Here comes the surprise, by the time you get to dispose your JavaScript object, your HTML elements might not be present in the document anymore.  The AJAX call could have updated the HTML already.  That was the cause of the leak with the treeview -- document.getElementById(...) returned the newly replaced root element while the old one leaked.  To make matters worse, there was no way to obtain a reference and unhook those events anymore.

The solution is simple.  Forget the best practices and use your better judgement!  All you need is to keep an additional reference to those DOM elements.  Don't get them by ID and remember to release the reference when you are done:

============= the fixed version ====================

RadTreeView.prototype.AttachEvents = function()
{
    this.RootElement = document.getElementById(this.RootElementID);
    //attach the event handlers
}

RadTreeView.prototype.Dispose = function()
{
    var rootElement = this.RootElement;
    //clean up rootElement event handlers here
    this.RootElement = null;
}

==============================================

Go get the tool and check if your resource disposal works with AJAX updates.  Happy hunting .



rahnev
About the Author

Stefan Rahnev

Stefan Rahnev (@StDiR) is Product Manager for Telerik Kendo UI living in Sofia, Bulgaria. He has been working for the company since 2005, when he started out as a regular support officer. His next steps at Telerik took him through the positions of Technical Support Director, co-team leader in one of the ASP.NET AJAX teams and unit manager for UI for ASP.NET AJAX and Kendo UI. Stefan’s main interests are web development, agile processes planning and management, client services and psychology.

Related Posts

Comments