[Okta Webinar] Learn how to a build a cloud-first strategyRegister Now

x
?
Solved

AJAX Memory Leak?

Posted on 2007-08-09
18
Medium Priority
?
679 Views
Last Modified: 2013-11-05
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
Comment
Question by:jls33fsls
  • 9
  • 7
  • 2
18 Comments
 
LVL 75

Expert Comment

by:Michel Plungjan
ID: 19668061
What framework, do you kill the xmlhttp object after use?
0
 

Author Comment

by:jls33fsls
ID: 19668087
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
 
LVL 75

Expert Comment

by:Michel Plungjan
ID: 19668094
Why not use a framework like prototype.js - some clever people have thought about and tested these things
0
Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 

Author Comment

by:jls33fsls
ID: 19668104
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
 
LVL 75

Expert Comment

by:Michel Plungjan
ID: 19668109
     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
 

Author Comment

by:jls33fsls
ID: 19668143
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
 

Author Comment

by:jls33fsls
ID: 19668160
Actually, in IE it doesn't work at all, it sends stuff, but doesn't receive anything back.
0
 
LVL 75

Accepted Solution

by:
Michel Plungjan earned 2000 total points
ID: 19668189
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
 

Author Comment

by:jls33fsls
ID: 19668223
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
 
LVL 75

Expert Comment

by:Michel Plungjan
ID: 19668229
prototype only loads what it needs. It does not have a huge overhead and is cached on the client
0
 

Author Comment

by:jls33fsls
ID: 19668242
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
 
LVL 75

Expert Comment

by:Michel Plungjan
ID: 19668296
:)
0
 
LVL 16

Expert Comment

by:LeeKowalkowski
ID: 19668424
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
 

Author Comment

by:jls33fsls
ID: 19672288
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
 
LVL 75

Expert Comment

by:Michel Plungjan
ID: 19672332
I have not seen anything special with dhtml. Of course poorly written code may give leaks using any methods...
0
 

Author Comment

by:jls33fsls
ID: 19672443
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
 

Author Comment

by:jls33fsls
ID: 19673871
Hm, seems like using prototype didn't fix the memory leak in firefox though.
0
 
LVL 16

Expert Comment

by:LeeKowalkowski
ID: 19682210
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

Featured Post

Free Tool: Site Down Detector

Helpful to verify reports of your own downtime, or to double check a downed website you are trying to access.

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.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

When it comes to security, close monitoring is a must. According to WhiteHat Security annual report, a substantial number of all web applications are vulnerable always. Monitis offers a new product - fully-featured Website security monitoring and pr…
In this blog, we’ll look at how improvements to Percona XtraDB Cluster improved IST performance.
The viewer will learn the basics of jQuery including how to code hide show and toggles. Reference your jQuery libraries: (CODE) Include your new external js/jQuery file: (CODE) Write your first lines of code to setup your site for jQuery…
Want to learn how to record your desktop screen without having to use an outside camera. Click on this video and learn how to use the cool google extension called "Screencastify"! Step 1: Open a new google tab Step 2: Go to the left hand upper corn…
Suggested Courses
Course of the Month20 days, 1 hour left to enroll

873 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question