Wednesday, May 30, 2012

Why does jquery leak memory so badly?


This is kind of a follow-up to a question I posted last week: http://stackoverflow.com/questions/2429056/simple-jquery-ajax-call-leaks-memory-in-ie



I love the jquery syntax and all of its nice features, but I've been having trouble with a page that automatically updates table cells via ajax calls leaking memory.



So I created two simple test pages for experimenting. Both pages do an ajax call every .1 seconds. After each successful ajax call, a counter is incremented and the DOM is updated. The script stops after 1000 cycles.



One uses jquery for both the ajax call and to update the DOM. The other uses the Yahoo API for the ajax and does a document.getElementById(...).innerHTML to update the DOM.



The jquery version leaks memory badly. Running in drip (on XP Home with IE7), it starts at 9MB and finishes at about 48MB, with memory growing linearly the whole time. If I comment out the line that updates the DOM, it still finishes at 32MB, suggesting that even simple DOM updates leak a significant amount of memory. The non-jquery version starts and finishes at about 9MB, regardless of whether it updates the DOM.



Does anyone have a good explanation of what is causing jquery to leak so badly? Am I missing something obvious? Is there a circular reference that I'm not aware of? Or does jquery just have some serious memory issues?



Here is the source for the leaky (jquery) version:




<html>
<head>
<script type="text/javascript" src="http://www.google.com/jsapi"></script>
<script type="text/javascript">
google.load('jquery', '1.4.2');
</script>
<script type="text/javascript">
var counter = 0;
leakTest();
function leakTest() {
$.ajax({ url: '/html/delme.x',
type: 'GET',
success: incrementCounter
});
}
function incrementCounter(data) {
if (counter<1000) {
counter++;
$('#counter').text(counter);
setTimeout(leakTest,100);
}
else $('#counter').text('finished.');
}
</script>
</head>
<body>
<div>Why is memory usage going up?</div>
<div id="counter"></div>
</body>
</html>



And here is the non-leaky version:




<html>
<head>
<script type="text/javascript" src="http://yui.yahooapis.com/2.8.0r4/build/yahoo/yahoo-min.js"></script>
<script type="text/javascript" src="http://yui.yahooapis.com/2.8.0r4/build/event/event-min.js"></script>
<script type="text/javascript" src="http://yui.yahooapis.com/2.8.0r4/build/connection/connection_core-min.js"></script>
<script type="text/javascript">
var counter = 0;
leakTest();
function leakTest() {
YAHOO.util.Connect.asyncRequest('GET',
'/html/delme.x',
{success:incrementCounter});
}
function incrementCounter(o) {
if (counter<1000) {
counter++;
document.getElementById('counter').innerHTML = counter;
setTimeout(leakTest,100);
}
else document.getElementById('counter').innerHTML = 'finished.'
}
</script>
</head>
<body>
<div>Memory usage is stable, right?</div>
<div id="counter"></div>
</body>
</html>


Source: Tips4all

3 comments:

  1. My initial thought would be that it has something to do with the way the jquery ajax method either:

    a. creates circular references, especially bad for IE

    b. creates properties on internal objects which cannot be deleted due to the way they have been created and the setting of the DontDelete property. See this for more info: http://perfectionkills.com/understanding-delete/

    Either way, the garbage collector would be prevented from picking up the trash, which would result in a runaway memory leak, especially if that suspect function is executing frequently.

    ReplyDelete
  2. I found a related Ajax question on Stack Overflow that may help you.

    ReplyDelete
  3. Maybe it is related to this : http://forum.jquery.com/topic/performance-issues-using-ajax-async

    ReplyDelete