Oh boy, not another memory leak post!  We already got a couple here and there.

JavaScript development is so frustrating at times that every little victory counts.  The seemingly memory-managed, easy-to-write script language sometimes is harder than C++, and believe me, I've had my fair share of C++, Win32  and COM development.  As if it's not enough that you have to deal with each and every browser's way of implementing the "standard", but now you have to manage and free your own memory.

Memory leaks have not been a big problem most of the time.  Well, a leaked <div> or <td> here or there didn't hurt anyone and people were generally happy.  Then we got hit by the AJAX tsunami.  People are updating large portions of their pages, and they do that all the time.  Nobody cares to unhook their event handlers or clean their DOM references, huge DOM object hierarchies leak like crazy.  Welcome to Web 2.0!  May I have an extra gigabyte of RAM for that iexplore.exe, please?

But I digress.  Pardon my bitterness, this is supposed to be a tool post after all.  The most famous, well actually, the only tool for checking for memory leaks under IE is Drip.  It hosts an IE instance and allows you to load your page, play with it and then hit the "Check Leaks" button just to have it list the DOM elements that you were supposed to clean up.  I like the tool.  It helps tremendously in the leak hunt, but... guess what... it's not perfect.  We saw that when we were pairing today, trying to find and eliminate the cause of a leak in our CallbackPanel control.  Updating controls inside the panel worked like a charm, the only problem being that memory usage grew steadily over time.  Drip showed nothing.  It looked like we have the perfect page, and yet that lost memory made us feel uneasy.

I've had enough of it all, so I downloaded Drip's source code.  This is my first dealing with C++ for the past two years, and the ASCII art made me cringe (**, ->, <,> anyone?).  Anyway I bit the bullet and got to the JS object hook class that "told" me the bitter truth.  Drip keeps track only of DOM elements that:
  • have been initially rendered on the page
  • have been created by document.createElement(...)
  • have been cloned from an existing element via element.cloneNode()

That's it!  Everything else might leak and it will go undetected by the tool.  Here is an example:

function DripDetectable()
{
    var container = document.getElementById("container");
    for (var i = 0; i < 100; i++)
    {
        var link = document.createElement("A");
        link.innerHTML = "test1";
        link.circular = link;
        container.appendChild(link);                       
    }
}

This function will create 100 links that will leak because of the deliberate circular reference (the circular expando property points to the link itself).  Drip will detect those, because they were created by calling document.createElement(...). 



Here is something completely different:

function DripInvisible()
{
    var container = document.getElementById("container");
    for (var i = 0; i < 100; i++)
    {
        var linkText = "<a id='link" + i + "'>test2</a>";
        container.innerHTML += linkText;
       
        var link = document.getElementById("link" + i);
        link.circular = link;     
    }
}

This function creates another 100 of links, but this time it uses string concatenation and innerHTML to create the links.  The links have the same circular reference and really do leak.  The memory usage of iexplore.exe keeps going up when you refresh the page.  Drip, sadly, reports nothing.




Yes, I know innerHTML is a nonstandard property and should be avoided, but it's so damn convenient, and there are those times that you just can't implement something without it.  We have two options right now: decrease the innerHTML usage or augment the Drip tool, so that it detects those leaks.  Digging through a COM-infested C++ project (oh ATL and MFC too) does not make me happy, so I'll research the first option. 

I will keep you posted with any workarounds that we find and possibly other funny ways to leak and annoy your customers :-).  Good luck with your leaks.


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