What is memory leak? How to avoid memory leak in JavaScript?

Memory leak in JavaScript

A memory leak is nothing but an orphan block of memory on the heap that is no longer used by the application. It has also not been returned to the operating system by the garbage collector. This block of memory is always occupied and not reusable.

JavaScript uses Mark-and-sweep algorithm for garbage collection. Most garbage collectors use an algorithm known as mark-and-sweep.

In JavaScript, memory leaks are caused by unwanted references. A memory leak is a bug in the code. A memory leak can be caused by many different reasons. Following are some of the reasons for memory leak:

Accidental global variables

Global variables are never disposed of by the garbage collector (GC). After using the global variable if we set it to null then the memory that it references to be garbage collected.

function getUser(params) {
    // Unwanted global variable causes memory leak
    message = "Message of global variable";
}
console.log(window.message);

Global variable garbage collection:

function getUser(params) {
    // Unwanted global variable causes memory leak
    message = "Message of global variable";
    /* do all the required work */
    message = null;
}

Forgotten callbacks

setInterval is quite handy to implement observers in JavaScript. It takes a callback and it remains active unless we do clearInterval.

As we have used the variable data inside callback and we didn’t call clearInterval, the variable data will not be garbage collected.

var data = 'data from a source'; // data can not be garbage collected
setInterval(() => {
    var elementObj = document.getElementById('element');
    if(elementObj) {
        elementObj.innerHTML = data; // variable data is used inside callback
    }
}, 5000);

Forgotten callbacks garbage collection:

var data = 'data from a source';
const refreshIntervalId = setInterval(() => {
    var elementObj = document.getElementById('element');
    if(elementObj) {
        elementObj.innerHTML = data;
    }
}, 5000);

/* later */
clearInterval(refreshIntervalId);

Out of DOM references

Out of DOM reference means that the nodes which have been removed from the DOM but are still retained in memory. As long as the DOM node has a reference to a variable, the DOM node is not garbage collected even after being removed from the DOM.

let elementObj = document.getElementById('element');

// Do all the required tasks elementObj

(function() {
    // Here DOM node element is detached from the DOM but still retained in memory.
    // The reason is it has reference in elementObj variable
    document.body.removeChild(document.getElementById('element')); // DOM node element will not be garbage collected from the DOM tree. 
})();

Out of DOM references garbage collection

let elementObj = document.getElementById('element');

// Do all the required tasks elementObj

(function() {
    // Here DOM node element is detached from the DOM but still retained in memory.
    // The reason is it has reference in elementObj variable
    document.body.removeChild(document.getElementById('element'));
})();

/* later */
elementObj = null;

Closures

A memory leak occurs in a closure too. When a variable is declared in outer function and it is available to the nested inner function. The variable can be in memory even if it is not being used/referenced in the nested function.

Reference: