roshan
roshan

Reputation: 2510

Memory leak in IE: Due to ajax call using .load()

I am loading entire data of .html files in a div via ajax call. The html page contains link,script tags required for HTC(html component) to bind with the elements on page.

The structure of the page is like:

enter image description here I am using jQuery to load HTML pages like this

<body>
<input type="radio" class="openpage" id="0001">
<input type="radio" class="openpage" id="0002">
<input type="radio" class="openpage" id="0003">
<input type="radio" class="openpage" id="0004">

<div id="loadPage"></div>
<script>
$(document).ready(function(){
  $(".openpage").on("click",function(){
    $("#loadPage").load($(this).attr("id")+".html",function(){
    //load a page with many htc bindings and external references

    //trigger some onload functions which are not called automatically in IE
    //confirmed this is in chrome

    });
  });
})
</script>

</body>

The problem with this is that IE memory keeps pilling up as radio buttons are clicked to load pages and after loading few pages browsers stops responding. I can see the memory going up in task manager.

The application runs in IE 5,6,7,8,9 and in quirks mode in IE10. I tried to replicate the same scenario in chrome and it showed no problem. So I think it is IE specific memory management related problem.

I read many articles but I was not convinced.I also read this question on SO but it suggests to load only some part of page which is not acceptable in my case.This article seems relevant but I am not sure what exactly causes memory leak in my case.

The entire body above is actually in a iframe . So as a workaround I reload the frame with the main page containing after 8 clicks of radio button. I have tried to clear stuffs before each load using:

$("#loadPages").empty();

$("#loadPages").find("*").off();

$.ajaxSetup({ cache: false });

But nothing works.So I doubt whether jquery can clear events registered through htc.

1) It would be great if you explain the reason of memory leak in this case.

2) And in general why memory leak can occur in a browser after loading many resources. This does not happen in modern browsers but why it occurred in older browsers.

3) Is there a way to release browsers memory without refreshing the frame.

4)Is there a way to check what all resources are residing in a browsers memory.

Upvotes: 3

Views: 1067

Answers (2)

Kakashi Hatake
Kakashi Hatake

Reputation: 3026

Have you ever consider to use xhr requests? They can load the content to your target using ajax. I did a sample fiddle to your question. Have a look at it. Cheers.

Snippet

function getXmlHttpRequest() {
  var xmlhttp;
  if (window.XMLHttpRequest) {
    xmlhttp = new XMLHttpRequest();
    // code for IE7+, Firefox, Chrome, Opera, Safari

  } else if (window.ActiveXObject) {
    xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
    // code for IE5 and IE6
  } else {
    alert("Browser doesn't support Ajax..!!");
  }

  return xmlhttp;
}

function loadPage(pageTitle) {
  //pageTitle = pageTitle + ".html";
  xmlhttp = getXmlHttpRequest();
  if (xmlhttp != null) {
    xmlhttp.onreadystatechange = function() {
      if (xmlhttp.readyState < 4) {
        document.getElementById('loadPage').innerHTML = "Content Loading...!";
      } else if (xmlhttp.readyState == 4) {
        var res = xmlhttp.responseText;
        document.getElementById('loadPage').innerHTML = res;
      }
    }
    xmlhttp.open("GET", pageTitle, true);
    xmlhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
    xmlhttp.send(null);
  }
}

function showAlert() {
  alert("This is me!");
}
$(document).ready(function() {
  $(".openpage").on("click", function() {
    loadPage($(this).attr("id"));
  });
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<input type="radio" class="openpage" name="radio-group" id="https://dl.dropboxusercontent.com/u/105580681/xhr-fiddle/0001.html">
<input type="radio" class="openpage" name="radio-group" id="https://dl.dropboxusercontent.com/u/105580681/xhr-fiddle/0002.html">
<input type="radio" class="openpage" name="radio-group" id="https://dl.dropboxusercontent.com/u/105580681/xhr-fiddle/0003.html">
<input type="radio" class="openpage" name="radio-group" id="https://dl.dropboxusercontent.com/u/105580681/xhr-fiddle/0004.html">
<div id="loadPage"></div>

In this fiddle, i'm loading the html files using dropbox links. You can use your initial idea of 0001 - 0004 id numbers.
However if you are loading the entire content of a html page this will load everything from that external html page to inside of your targeted main page.

Example:

<div id="loadPage">
        <title>TODO supply a title</title>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <div>Content of HTML 0001 Page</div>
</div>

This will affect to your DOM file of the main page. Page functionality won't loose but it is not a good programming technic. So you probably need to write or load the content in xxxx.html files that you want to show on targeted element.

Learn more from
Using XMLHttpRequest Mozilla MDN
Using FormData Objects Mozilla MDN

Upvotes: 1

Tracker1
Tracker1

Reputation: 19334

You have a couple of workflows:

  • Replace existing DOM structures by dynamically loaded structures.
  • Wire in additional event handling after load.

From here:

  • When removing/replacing DOM nodes, events are still bound
  • By being bound to event handlers, the DOM nodes may not be able to clear
  • DOM nodes persist in memory, detached from the UI, but still leaking memory.

Your options are:

  • Make certain to clear all events on existing structures before clearing those nodes from the DOM, and allowing the new content to load.
  • Have several nodes for display, and load each only one time.
  • Check if a node exists, and simply detach it, rather than try to replace it.

IE has separate COM channels for the JavaScript and the Rendering engine, this means that sometimes, particularly with event binding. Objects/state in JS can hold on to references to UI/DOM nodes... and DOM nodes can reference JS event handlers. In many cases this means that those portions won't be garbage collected leading to inflated memory usage. It was far worse with earlier versions, but still happens.

You can have similar issues with other browsers, but IE tends to display this behavior much sooner. This also happens more with long-living single page applications.

If you only load each resource once, into its' own DOM node, you can simply detach/reattach that node. Also, you can rely on event propagation to listen to events from the parent node. Either of these will reduce the risk of contention, and overhead.

As to unregistering your event handlers, jQuery does a better job than most with this, as long as you register with jQuery, and use jQuery to remove/delete the node (and its' children).

Upvotes: 4

Related Questions