Fixing memory leaks of Internet Explorer 6
Lately we experienced a lot of performance problems in our AJAX applications. Since we went online a year ago we always had problems with users of Internet Explorer 6 but within the last three months they got more and more.
We already knew that this had something to do with the huge memory amount the Internet Explorer 6 uses after some hours of working with our application. I used the Process Explorer to analyze which page causes the problem. After identifying the page I did some reloads of it and generated the following image:
As you can see, with every reload the memory amount consumed by the Internet Explorer 6 increased (for about 2 megabytes). This memory amount was never released, even if a complete different page of the application was loaded. The only way to release the memory again was to close the instance of the browser.
I did a web search and found this interesting link about “Understanding and Solving Internet Explorer Leak Patterns”. It describes four different situations that could lead to memory leaks in Internet Explorer by using good graphics and example code.
I was really shocked when I realized that the Internet Explorer 6 holds those elements in memory even after the user left the page and loaded another one. In other browser it is just important to make sure that inside the page the references to elements are released proper when working with a lot of AJAX code without reloading the page.
We are using prototype and scriptaculous as JavaScript libraries. Another library used to display a clickable calendar for date input fields is the JSCalendar from dynarch.com. To find out which elements of the DOM and which script code cause the memory leak I searched for another tool and found sIEve.
With sIEve it was easy to detect to suspicious elements. After reloading the page inside of sIEve a lot of possible leaks were detected and the list looked like this:
By looking through the code of the page I found out that all the elements in the list had events registered (onclick, onkeyup, onchange, …) and the assigned methods contained closures (see this link for details again).
Some were caused by the used calendar library. I already sent an email to the author Mihai Bazon. He wrote a very good article about the problem and I could not believe that there is exactly that bug inside his library. Maybe we are using it incorrect.
The other leaks were caused by prototype. Although prototype has a built in mechanism that should unlink registered events when the page is unloaded they survived the reload. I found out that there is a bug in the 1.6.0 version of prototype. The mechanism was changed between version 1.5 and 1.6. This explained why the problem got bigger after updating out application to the new prototype version.
To fix the problem I registered a method to the unload event of the page that removes all the critical registered events. This looks like:
function breakLeaks() {
$('img_calendar').onclick = null;
Event.stopObserving("fieldX", "keyup", keycheck, false);
Event.stopObserving("fieldX", "click", mousecheck, false);
...
}
Event.stopObserving("window", "unload", breakLeaks, false);
After changing the page like that I tested it again with sIEve and no more leaks were detectd. Then I used the Process Explorer again to monitor the memory consumption of the Internet Explorer. The graph now looked like:
The memory footprint is a lot smaller now and memory allocated by the reload was completely released again.