Memory Leaks in NodeJS | Quick Overview
Have you ever got involved in any large scale NodeJs application? If Yes, So you know what we are talking about, if No, then you need to continue reading as you might face it soon, as I did 😄. Memory leak is very common in NodeJs Applications especially large scale ones with reasonable traffic, and many big companies have suffered from it. let’s know why?
NodeJs applications are long-running processes, the application is initiated once, then it is up and running, handling all incoming requests and consuming resources continuously.
Unlike PHP which creates a child process for every incoming request, initiates the app for it and once the request is done the process is terminated and all resources are released.
This fact gives NodeJS applications advantages as the application is initiated only once not for each incoming request and at the initiation you can add all your configs, DB connections, routes, etc. This makes handling requests faster as it only does the logic for each request with no need for repetitive work, also it saves resources required for this initiation process.
But Nothing comes without a price as for this advantage you have to take care of your application memory usage as it will be consuming your memory continuously during its run-time, and if you aren’t handling your memory usage efficiently, you may run out of memory, Then you’ll have to restart your app to free up the memory.
Memory Management in NodeJs:
Memory Management in NodeJs is done via V8: ‘which is the engine that makes it possible to run JavaScript on the server outside the browser’.
V8 is handling two main memory categories:
Stack: In which it stores the primitive data types: Number, String, boolean, Null, Undefined, Symbol
and references to non-primitive data types Object
.
Heap: stores the non-primitive data types: Object
.
The V8 has a garbage collector runs mainly Mark and Sweep
algorithm:
It checks for all objects’ reference paths to the root node ‘which is the global
or window
object’. If any reference has no path to the root node, it will be marked as garbage and will be swept later.
Important Note: When the Garbage Collector runs, it pauses your application entirely until it finishes its work. so you need to minimize its work by taking care of your objects’ references.
Most Common Causes:
According to what we explained in Memory management, We can define three of the most common memory leak causes, you need to be careful while using them in your code.
Global Variables
As they have a direct path to the root node, they will stay in memory as long as the application is running so you need to be careful when setting global variables and the amount of data you’ll set to them.
Multiple References
Setting multiple references to the same object may cause a problem also as you may remove one ref and forget the other which will keep your object still exists in the Heap.
Closures
In closures simply you keep references to objects to be used later. this feature has many advantages but if it’s used without caution it may cause big issues as these references will keep objects in heap and these objects might be large ones, not just simple objects.
How To Detect
There’re many tools and libraries used to detect memory leaks in NodeJS, all following the same concept to detect memory leaks by comparing different heap dumps and check the results, and they try to force run the garbage collector before taking any heap dump to make sure that the leakage is real.
The difference between two heap dumps is an indicator of the amount of memory leak in your application. I would go with two of these tools, the most important ones from my point of view:
- Node-Memwatch: Very helpful in the production as it emits specific events once there’s abnormal memory usage or potential leak in your app so you can handle these events or expect that there’s a problem coming😄.
- Node-Inspector: Very useful especially when used with Chrome DevTools in the development phase as it enables you to perform stress tests on your application and monitor the memory usage performance to check if there’s any potential leak in your code and find where exactly that leak might happen.
Quick Demo on Node-Inspector & Chrome DevTools:
- Firstly, run your app with options:
expose-gc
to be able to run the garbage collector explicitlyinspect=9222
to be able to attach the Chrome Debugger to your app on port9222
so the command should be:
node --expose-gc --inspect=9222 app.js
- now open this URL
chrome://inspect
from your Chrome to open chrome devices inspector
then you need to check that you have your server host with debugging port added to the list of the target discovery servers.
after adding your server to the list, it will show up in the remote targets. just click inspect
.
this will open a new dedicated window for debugging your app. in Memory tab you would find an option to collect garbage, take heap snapshots and monitor allocation timeline.
In the screenshot below you can find on the upper left corner the button to enforce running garbage collector and in the middle the button to take heap snapshots.
Now we need to take two snapshots one at the start and the other after making some calls to the server for a specific route if you wanna check specific logic or some random routes if you wanna check the overall performance.
and also don’t forget to enforce running the garbage collector before each snapshot.
After taking the second snapshot there’s a select menu on the top.
Choose from it Objects allocated between Snapshot1 and Snapshot2
this is to get the difference between the two snapshots as these objects are the potential leakage in your app.
You’ll find two sections for Constructors and Retainers, first you shall focus on constructors without braces then you may check others.
After checking the constructor, you may check its retainers, you shall find indications from your source code to where the leakage is, the leakage also may be from third parties you use.
Important notice: try to take many heap snapshots and between them make some requests to your server and check if the memory usage increasing or still the same if it’s stable so you’re safe otherwise you have an issue.
Finally, That was just a quick overview on the main parts of the memory leak problem, We may speak in more details for each part of those, but I wanted to make it a quick overview about this mysterious topic, So if you like it show your support by claps and share.
References:
- https://blog.risingstack.com/finding-a-memory-leak-in-node-js/
- https://www.toptal.com/nodejs/debugging-memory-leaks-node-js-applications
- https://auth0.com/blog/four-types-of-leaks-in-your-javascript-code-and-how-to-get-rid-of-them/
- https://www.alexkras.com/simple-guide-to-finding-a-javascript-memory-leak-in-node-js/
- https://developer.chrome.com/devtools/docs/memory-analysis-101