views:

547

answers:

2

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"&gt;&lt;/script&gt;
    <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"&gt;&lt;/script&gt;
    <script type="text/javascript" src="http://yui.yahooapis.com/2.8.0r4/build/event/event-min.js"&gt;&lt;/script&gt;
    <script type="text/javascript" src="http://yui.yahooapis.com/2.8.0r4/build/connection/connection_core-min.js"&gt;&lt;/script&gt;
    <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>
+1  A: 

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

Gaby
+1  A: 

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

aSeptik
Thanks. Most of that post deals with cleaning up the DOM when removing elements, which my test script doesn't need to do. However, the comment recommending isolating setTimeout was interesting.
Thomas Lane
yeah! it's a nice trick! ;-)
aSeptik