How To Troubleshoot JavaScript Memory Leaks

November 26, 2019

Memory leaks in server side JavaScript with Node.js can cause your server to crash and reboot constantly in a cycle, which can negatively impact your site and service availability and uptime, particularly if you don’t have good redundancy.

Memory leaks in client side JavaScript will cause your website or application to progressively get slower and slower over time, and will eventually freeze or crash the browser tab. This is a significantly negative experience for your users.

Memory leaks in JavaScript tend to come from 3 main things. Here are some general things to look for when troubleshooting memory leaks in JavaScript code.

1. Caches or global variables that hold data

Local data caches are one of the most likely culprits of memory leaks. This is doubly true if there is no logic in place that limits or controls the size of the cache, like a max. number of items that can be put in it, or a max. memory size.

Look for assignments like pushing items into an array or filling a global cache variable that exists outside a function:

let itemsCache = new Set();

function cacheItems(items) {
  items.forEach(item => {
    if (!itemsCache.has(item)) {
      itemsCache.push(item);
    }
  });
}

2. Event listeners that are not cleaned up

Manually bound event listeners that are not cleaned up or unbound after the DOM changes can continue to hold memory for any referenced variables and functions, even though the event itself may never be triggered again. When the DOM element is removed without removing the attached event handlers too, it can prevent garbage collection of all of the referenced data objects, functions, and other code, which can eventually lead to bloated memory that will never be automatically cleaned up.

It’s worth noting that this does not apply when using modern DOM frameworks like React, Vue.js, Angular, etc. as those frameworks will automatically cleanup any attached event listeners for you. For that reason, this is much less of a problem today than it has been in the past.

3. Recursion (can be loops or setInterval calls)

The third thing to look for when dealing with possible memory leaks is recursion. A simple loop that has never caused an issue with 100 items might suddenly start bringing down your whole site with 10,000 items.

Any setInterval calls that are done server-side (or client-side, but also executed server-size if you are server-side rendering) that are not also cleared using a corresponding clearInterval can cause memory buildups.

Manual Debugging

If you need to poke around and do a little manual debugging, you can start node with the –inspect flag, and your browser (like Chrome) can connect to it over websockets and provide the same profiling and debugging tools that you enjoy in the browser.

You can also use console.log to manually log out the memory usage after certain calls and in certain areas of the application in Node.js:

const memoryUsed = process.memoryUsage().heapUsed / 1024 / 1024;
console.log(`Memory Used: ${memoryUsed} MB`);


Tags: , ,

Categories: ,