Memory leaks can be very hard to indentify. Most of the time this is because the amount of memory that leaks is so small you won’t see it all at once on the process task manager. There are things that you can do that will prevent memory leaks or at least allow the page to be fully collected when the page reloads. It seems in my research that it is very hard to get 100% leak free in all browsers. But you will be able to reduce the amount of leaks to a minimal level. With that in mind it will help you to know the best practices to avoid the major risk of memory leaks.
Two of the most common memory leaks are:
- Attaching a JavaScript object to a dom node and not removing it before the dom node is removed.
Will Leak Example:
var div = document.createElement("div");
div.bigString = new Array(1000).join(new Array(2000).join("XXXXX"));
document.body.appendChild(div);
div.parentNode.removeChild(div);
Will Not Leak Example:
var div = document.createElement("div");
div.bigString = new Array(1000).join(new Array(2000).join("XXXXX"));
document.body.appendChild(div);
delete div.bigString;
div.parentNode.removeChild(div);
Note:
You will want to avoid attaching js objects to a dom node. It will use more memory and will have to be removed individually. A much better way would be to create a js object and then reference the dom node. As always remember to clean up the js objects/events first before removing the dom nodes. Javascript’s Garbage Collector is able to detect circular references and handle them correctly, but the DOM’s Garbage Collector can not. - Referencing a variable outside the scope of a dom element’s event function (formally known as a closure see http://www.jibbering.com/faq/faq_notes/closures.html for more information). The problem is that the variable and function become intertwined due to the reference and will not be collected unless both are freed (won’t happen until page unload for global variable references). If the event is never removed/released the garbage collector will never collect both the object and the dom fully.
Will Leak Example:
var bigString = new Array(1000).join(new Array(2000).join("XXXXX"));
var d = document.createElement("div");
d.onclick = function() {
this.innerHTML = bigString.length;
};
document.body.appendChild(d);
d.parentNode.removeChild(d);
Will Not Leak Example:
var bigString = new Array(1000).join(new Array(2000).join("XXXXX"));
var d = document.createElement("div");
d.onclick = function() {
this.innerHTML = bigString.length;
};
document.body.appendChild(d);
bigString = null;
d.onclick = null;
d.parentNode.removeChild(d);
The 2nd example seems to be the most common and the most hard to correct. Most of the time you can get around the closure leak by making the information available in a global object. Attached is a html file with the above example with a proper removal and an improper removal. A helpful tool to find memory leaks can be found at http://blog.j15r.com/2005/05/drip-ie-leak-detector.html.