• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 685
  • Last Modified:

AJAX Memory Leak?

I made a multiplayer AJAX poker game, but I seem to have some problems with browser memory leaks I guess.  I have the AJAX poll the server for data to update the table every 2 seconds and was wondering if anybody knew of some common or maybe not-so common issues in a setup like this that could cause excessive memory build up in the browser, or cause the user to be locked out of the site until they restart their browser.

Common symptoms are that the table just freezes, and then if they try and go to any page on the site it won't load, but any other site loads.  Then if they restart the browser everything works fine again.
0
jls33fsls
Asked:
jls33fsls
  • 9
  • 7
  • 2
1 Solution
 
Michel PlungjanIT ExpertCommented:
What framework, do you kill the xmlhttp object after use?
0
 
jls33fslsAuthor Commented:
I thought so, but maybe I did something wrong.

var get_it = "";
      
      function makeRequest(url) {
            var http_request = false;
            if (window.XMLHttpRequest) {
                  http_request = new XMLHttpRequest();
            } else if (window.ActiveXObject) {
                  try {
                        http_request = new ActiveXObject("Msxml2.XMLHTTP");
                  } catch (e) {
                        try {
                              http_request = new ActiveXObject("Microsoft.XMLHTTP");
                        } catch (e) {}
                  }
            }
            if (!http_request) {
                  alert('Your browser is too old to support PokerRPG.');
                  return false;
            }
            if (get_it != "no") http_request.onreadystatechange = function() { alertContents(http_request); };
            else get_it = "";
            http_request.open('GET', url, true);
            http_request.send(null);
      }

      function alertContents(http_request) {
            if (http_request.readyState == 4) {
                  if (http_request.status == 200) {
                        rec_content(http_request.responseText);
                        the_status = 0;
                  } else {
                        the_status++;
                        if (the_status >= 8) alert('Error: Connection failed.');
                  }
            }
      }
0
 
Michel PlungjanIT ExpertCommented:
Why not use a framework like prototype.js - some clever people have thought about and tested these things
0
Cloud Class® Course: Python 3 Fundamentals

This course will teach participants about installing and configuring Python, syntax, importing, statements, types, strings, booleans, files, lists, tuples, comprehensions, functions, and classes.

 
jls33fslsAuthor Commented:
How would using prototype help me here.  Would I not have to recode the whole thing?

Also you asked if I killed the xmlhttp object after use, is that not being done in the code I posted?
0
 
Michel PlungjanIT ExpertCommented:
     var get_it = "";
      var http_request = null;
      function createRequest() {
            if (http_request) return http_request;
            if (window.XMLHttpRequest) {
                  req = new XMLHttpRequest();
            } else if (window.ActiveXObject) {
                  try {
                        req = new ActiveXObject("Msxml2.XMLHTTP");
                  } catch (e) {
                        try {
                              req = new ActiveXObject("Microsoft.XMLHTTP");
                        } catch (e) {}
                  }
            }
            if (!req) {
                  alert('Your browser is too old to support PokerRPG.');
            }
            return req;
      }
      function makeRequest(url) {
            http_request = createRequest();
            if (get_it != "no") http_request.onreadystatechange = function() { alertContents(http_request); };
            else get_it = "";
            http_request.open('GET', url, true);
            http_request.send(null);
      }

      function alertContents(http_request) {
            if (http_request.readyState == 4) {
                  if (http_request.status == 200) {
                        rec_content(http_request.responseText);
                        the_status = 0;
                  } else {
                        the_status++;
                        if (the_status >= 8) alert('Error: Connection failed.');
                  }
            }
      }
0
 
jls33fslsAuthor Commented:
Well that code is working, but firebug keeps giving me this error:

[Exception... "Component returned failure code: 0x80040111 (NS_ERROR_NOT_AVAILABLE) [nsIXMLHttpRequest.status]" nsresult: "0x80040111 (NS_ERROR_NOT_AVAILABLE)" location: "JS frame :: http://pokerrpg.com/p/no_limit_holdem.php :: alertContents :: line 391" data: no]
[Break on this error] if (http_request.status == 200) {
0
 
jls33fslsAuthor Commented:
Actually, in IE it doesn't work at all, it sends stuff, but doesn't receive anything back.
0
 
Michel PlungjanIT ExpertCommented:
With prototype.js you would simply download it and add
<script type="text/javascript" src="prototype.js"></script>
to your page

then you would recode the http request part like this:

function makeRequest(url) {
  var myAjax = new Ajax.Request(url,  {method:"get", onComplete: showResponse});
}
function showResponse(originalRequest)  {
    alert(originalRequest.responseText);
}

Michel
0
 
jls33fslsAuthor Commented:
Hmm, well that looks like it might actually be stopping the memory leak, but is there anyway to just have the part that does the http request, because that is a lot to load that isn't being used.
0
 
Michel PlungjanIT ExpertCommented:
prototype only loads what it needs. It does not have a huge overhead and is cached on the client
0
 
jls33fslsAuthor Commented:
I just don't get how that stopped it, I am really excited that it seems to have (hopefully its not a fluke!), but it actually is dropping the memory usage interestingly enough, whereas before it went up by a little every 2 seconds.  I am going to wait and make sure it keeps up for a little longer, and if so looks like you have given me the solution:-)
0
 
Michel PlungjanIT ExpertCommented:
:)
0
 
LeeKowalkowskiCommented:
Sorry, memory leaks are more likely to be DHTML.  Using a library to attach events isn't necessarily the answer either.

AJAX just makes it worse, if you innerHTML some markup with onclick event handlers, then innerHTML over the top of that, blowing away what was previously there, that's a recipe for memory-leak disaster.

There are tons of references: http://msdn2.microsoft.com/en-us/library/Bb250448.aspx & http://www.codeproject.com/jscript/leakpatterns.asp.

Douglas Crockfords video explains it best: http://www.webstandards.org/2006/10/18/video-presentation-douglas-crockford-on-the-theory-of-the-dom/ - I can't remember which part he talks about memory leaks, perhaps it's part three.

--
Lee
0
 
jls33fslsAuthor Commented:
So having div layers and then updating them every few seconds with something like this causes a memory leak?  If so, how am I supposed to fix that?

document.getElementById('chatwindow').innerHTML = data2[0];
0
 
Michel PlungjanIT ExpertCommented:
I have not seen anything special with dhtml. Of course poorly written code may give leaks using any methods...
0
 
jls33fslsAuthor Commented:
Do I need to do something like this before setting it to a new value so it doesn't build up in memory, or is the way I do it now fine?

document.getElementById('chatwindow').innerHTML = null;
document.getElementById('chatwindow').innerHTML = data2[0];

Also, the video says you have to remove all event handlers from deleted DOM nodes, it must be done on nodes before they are replaced by changing innerHTML.  Is that setting it to null, or something else?  And is this saying that if I just update a div with innerHTML, it doesn't jus overwrite it, but the old stuff stays in the memory?
0
 
jls33fslsAuthor Commented:
Hm, seems like using prototype didn't fix the memory leak in firefox though.
0
 
LeeKowalkowskiCommented:
The problem in IE is it has two garbage collectors, one for DOM elements and one for JS.  So you shouldn't destroy any objects before explicitly breaking the connections between DOM and JS.  I have found in IE this normally means you need to:
 * Call detachEvent for every attachEvent, when finished (which normally means you need to write/use a sophisticated attachEvent routine (normally true anyway because of cross-browser differences).
 * If not using attachEvent, but doing obj.onclick=myFunc; - You'll also need to do obj.onclick=null explicitly.
 * If event handlers are inserted in inline HTML, I generally find these are OK (not 100% sure).
 * Add new elements to the document before adding any more elements to the new element.
 * Avoid massive closures, anonymous inline functions are the biggest culprit.  E.g:
    function foobar()
   {
      var divs = document.getElementsByTagName('div');
      for(var i = 0; i < divs.length; i++)
          divs[i].onclick = function(){...}
   }
    - this forms a closure around the divs collection.  The divs variable cannot be freed up automatically because the onclick handler has scope closure over it (The divs variable is in scope for the anonymous function, therefore the JS engine must keep it in memory whilst the function is in memory).  This would avoid that:

   function myOnclickHandler()
   {
      ...
   }
   function foobar()
   {
      var divs = document.getElementsByTagName('div');
      for(var i = 0; i < divs.length; i++)
          divs[i].onclick = myOnclickHandler;
   }
   - because no inner function is defined, the divs object falls out of scope once the foobar function has finished.  There is also the benefit of only one event handler function being created.

Firefox is a different beast.  It doesn't have a split-garbage collection issue and therefore generally performs much better.  A lot of leak issues are reported and fixed, but many are due to extensions/plug-ins rather than Firefox itself, e.g. Firebug, do you have Firebug installed?  

Here's a page about Firefox Memory Leak issues, one is AJAX related:  http://www.squarefree.com/2006/02/04/memory-leak-progress/

--
Lee
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

Join & Write a Comment

Featured Post

Free Tool: Port Scanner

Check which ports are open to the outside world. Helps make sure that your firewall rules are working as intended.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

  • 9
  • 7
  • 2
Tackle projects and never again get stuck behind a technical roadblock.
Join Now