Common JavaScript memory leak patterns
The following examples are JavaScript patterns that have historically contributed towards the creation of memory leaks. These examples are provided to teach others about those potential patterns to avoid memory leaks and so that, if a memory leak is discovered, application developers know what to look for in their own JavaScript code.
Iframe leak
In web applications, iframes display multiple documents. If the top document holds any reference to an object inside the iframe, even after the work object is closed, this can cause a memory leak. Removing an iframe allows its memory to be garbage collected without requiring internal cleanup. If an object outside of the iframe refers to an object inside the iframe then the iframe cannot be garbage collected.
Some patterns of iframe leaks are:
- The outer window has a reference to an object in the inner window from within the iframe
window.top.innerObject = someInsideObject
- There is a reference to an object in the inner window from the outside
innerObject = iframeEl.contentWindow.someInsideObject
- An event listener is added from the inner scope to the outer scope
window.top.document.addEventLister('click',function() {...});
- jQuery methods spawning from parent window to child - coupled with a pseudo selector
$(window.top.document)find("iframe:not(:visible)")
Accidental global variables
A reference to an undeclared variable creates a new variable inside the global object. In the case of browsers, the global object is window.
function example1(arg) {
example2 = "this is a hidden global variable";
}
If example2 was supposed to hold a reference to a variable only inside the scope of the foo function and you forget to use var to declare it, an unexpected global variable is created.
Initializing multiple variables at the same time can also lead to accident global variables.
var a = b = 10;//b becomes a global variable.
Detached DOM nodes
Ensure DOM references in JavaScript are nullified after the DOM nodes are removed from the document. A DOM node can only be garbage collected when there are no references to it either from the page's DOM tree or JavaScript code.
var detachedNodes: function create() { var ul = document.createElement('ul'); for (var i = 0; i < 10; i++) { var li = document.createElement('li'); ul.appendChild(li); } detachedNodes = ul; } document.getElementById('create').addEventListener('click'),create);
Clicking the button referenced in the above code creates a <UL> node with 10 <LI> children. These nodes are referenced by code but do not exist in the DOM tree making them detached DOM nodes. Nullifying detachedNodes after use would make the node eligible for garbage collection.
Event listeners
Memory leaks can be introduced if event listeners are not appropriately cleaned up when the DOM element that the event listener is being attached to is removed. Not removing event listeners can cause the listener to hang onto a reference of the element it was attached to. You should ensure that events are attached and detached using the same set of arguments
Duplicated JavaScript includes in <HEAD>
If you are writing a custom control or HTML fragment that includes JavaScript, that JavaScript often gets added to the <HEAD> of the document. If that custom control or HTML fragment is included inside of a work object that will cause the JavaScript to get added to the <HEAD> every time the control or HTML fragment is loaded. This can be avoided by wrapping the JavaScript include or JavaScript in a <pega:onlyonce> JSP tag.
Previous topic Memory and JVMs Next topic Detecting memory leaks in Pega applications