JavaScript Memory Management

Aug 04, 2019

In any program, a variable takes up some memory. In low-level programming languages such as C, the programmer must allocate and deallocate memory manually. In contrast, the V8 JavaScript engine and other modern JavaScript engines have garbage collectors that delete unused variables for the programmer. Despite this memory management done by the JavaScript engine, however, there are common pitfalls that developers can fall into.

Memory Leaks

A memory leak is a failure in a program to release discarded memory, causing impaired performance and sometimes even failure. Memory leaks can happen when JavaScript engines’ garbage collectors do not free memory properly.

Reference to an Object

If there is a reference to an object, it is in memory. In this example, say that the memory() function returns some array with 5KB of data.

  var foo = { 
      bar1: memory(), // 5kb 
      bar2: memory() // 5kb 
  } 
  
    function clickEvent(){ 
    	alert(foo.bar1[0]); 
    }

You might expect the clickEvent() function to use 5KB of memory since it is only referencing bar1 from the foo object. However, the truth is that it is using 10KB of memory since it has to load the whole foo object into the function’s into scope to access the bar1 property.

Leaking DOM

If a variable pointing to a DOM element is declared outside of an event callback, then it is in memory and leaks DOM if the element is deleted.

In this example, there are two DOM elements selected by document. getElementByID.

<div id="one">One</div>
<div id="two">Two</div>

The following JavaScript code demonstrates the DOM memory leak. When one is clicked, it removes two. When one is clicked again, it still tries to reference the removed two.

var one = document.getElementById("one"); 
var two = document.getElementById("two"); 
one.addEventListener('click', function(){ 
two.remove(); 
console.log(two); // will print the html even after deletion 
});

The event listener on the one element will cause the two to disappear from the web page when clicked. However, even if the DOM is deleted in the HTML, reference to it will remain if used in an event callback. When the two element is no longer in use, this is a memory leak and should be avoided.

This can easily be fixed so that it won’t cause a memory leak, as shown here:

var one = document.getElementById("one");
one.addEventListener('click', function(){ 
var two = document.getElementById("two"); 
two.remove(); 
});

Another way to address this is by unregistering the click handler once it has been used, as shown here:

var one = document.getElementById("one");
function callBackExample() { 
var two = document.getElementById("two"); 
two.remove(); 
one.removeEventListener("click",callBackExample); 
} 
one.addEventListener("click",callBackExample); 
})

Global window Object

If an object is on the global window object, it is in memory. The window object is a global object in a browser and comes with various built-in methods such as alert() and setTimeout(). Any additional objects declared as a property of window will not be cleared because window is a required object for the browser to run. Remember that any global variable declared will be set as a property of the window object. In this example, there are two global variables declared.

var a = "apples"; //global with var 
b = "oranges"; //global without var 
console.log(window.a); // prints "apples" 
console.log(window.b); // prints "oranges"

It is good to avoid global variables whenever possible. This will help save memory.

Limiting Object References

An object is cleared when all references are cleared. Always remember to limit the amount of scope the function pulls and pass the property of an object only into functions instead of the entire object. This is because the object’s memory footprint can be very large (e.g., an array of 100,000 integers for data visualization project); if only one of the object’s properties is needed, you should avoid using the entire object as a parameter.

For example, do not do this:

var test = {
prop1: 'test' 
} 
function printProp1(test){ 
console.log(test.prop1); 
} 
printProp1(test); //'test'

Instead, pass the property like this:

var test = { 
prop1: 'test' 
}
function printProp1(prop1){ 
console.log(prop1); 
}  
printProp1(test.prop1); //'test'

The delete Operator

Always remember that the delete operator can be used to delete an unwanted object property (though it does not work on nonobjects).

var test = { 
prop1: 'test'
} 
console.log(test.prop1); // 'test' 
delete test.prop1; 
console.log(test.prop1); // _undefined

Neeraj Dana

Experienced Software Engineer with a demonstrated history of working in the information technology and services industry. Skilled in Angular, React, React-Native, Vue js, Machine Learning