In Simple words, Memory leakage is defined as a memory that is not required by an application anymore but for sometimes these unwanted memories will not be returned to the operating system which will cause serious trouble. However, Memory leaks can be a serious problem in Node.js applications, especially in large scale applications that holds the reasonable traffic, it highly affects the application performance. On considering this serious impact, this blog focused to give a adequate practical guides to solve the memory leakage on Node js applications and to avoid it in future implementations.
The most common source of memory leakage are : Improper Global variables usage, Unhandled multiple References, incautious Closures, where we keep reference to objects for later usage.
Node JS memory management:
Node Js applications are executed by V8, an open source javascript engine by Google, although it was not designed specifically for Node. V8 deals with memory management on behalf of the Node.js applications. However, automatic memory management and certain complications with the V8 garbage collector also might lead to Node.js memory leaks.
The role of V8 is, it has the responsibility to allocate the memory to an object in a Node.js application and eventually it will begin the garbage collection will free up the memory when the available memory is about to dry. It must have to identify the regions of memory need to be reallocated without affecting the performance of the application. Also note to mind, the Memory which contains unreachable objects is called a “dead” region, and that can be safely be reallocated.
Tools To Trace Memory Leak:
-
NPM Heapdump module
Using the node NPM heapdump module, we can create a heap snapshot for inspection. The module can be easily added to our Node application using :
npm install heapdump --save
var heapdump = require('heapdump'); heapdump.generateSnapshot(function(err, filename) { console.log('Snapshot taken as :', filename); });
Capture and keep the snapshots in different timings, and use those snapshots to compare them. Node-inspector is another alternative to ‘heapdump’.
-
Google Chrome Dev Tools
The collected snapshots from ‘heapdump’ have to be loaded and compared using Google Chrome Development tools. This helps us to store the snapshots which are taken at different times. so we can figure out which objects were allocated and not freed up in the meantime.
-
Low-level Tools like mdb, gcore
Best To Read: How To Secure Node.js RESTful APIs With JSON Web Tokens
Guidelines to Prevent memory leakage
Always name closures and functions
While inspecting stack traces and heaps, it’s much easier to trace when all have their individual names.
db.query('GET ALL INVENTORIES', function getAllInventories(error, data) { ... })
Avoid large objects in hot functions
Avoid large objects inside of hot functions and perform all CPU and memory bound operations in background. Optimize the hot function, Using optimized hot functions use less memory than the usual ones and also, it causes GC to run less often.
Avoid memory dumping
Instead dumping the whole files in memory, try to read files as chunk, . For example a large CSV file should be read line-by-line here the entire files need not to be loaded in memory instead we can read as little chunks.
Do not block main server thread
CPU intensive operations will block main thread forcing all other customers to wait and keep sending requests. Assume, an API to handle read operations which requires further time to process which will block the main thread, in that case, it should be moved to a separate thread or should be turned as a background job. Also remember, those unprocessed request data should be made to null and all these will enable the GC to take care of the cleanup process.
Generate only needed data
Unnecessary data, logs dumping, should be avoided in Production / Live environment so the full GC kicks will occur after some decent interval of time. This will helps V8 heap to create objects and to be allocated in New Space rather than in Large Object Space.
Standardize tools usage
There are several debuggers, identifiers, tracers and usage graphs generators are available. Use those tools to make your software faster and more efficient.
Triggering Garbage Collection
Node support us for triggering Garbage Collection GC. It helps us to trace the initial step to confirm a memory leak. This can be accomplished by running Node with –expose-gc flag (i.e. node –expose-gc index.js). Once node is running in that mode, you can programmatically trigger a Garbage Collection at any time by calling global.gc() from your program.
The amount of memory used by your process is known by calling process.memoryUsage().heapUsed.
Related: How To Interact With Database Using Async Module In Node.js
Sample Program
With Memory Leakage:
The following program demonstrates the usual process of writing the logs for every incoming requests which is the main reason of continuous memory leaks thats only required on final response.
const http = require('http'); const heapdump = require('heapdump'); let incomingRequestLogs = []; let server = http.createServer((req, res) => { if (req.url === '/heapdump') { heapdump.writeSnapshot((err, filename) => { console.log('Heap dump written to', filename) }); } incomingRequestLogs.push({ url: req.url, date: new Date() }); res.end(JSON.stringify(incomingRequestLogs)); }); server.listen(3000); console.log('Server listening to port 3000. Press Ctrl+C to stop it.'); console.log(`Heapdump enabled`);
Without Memory Leakage:
Here in the following program, you can note how the logs are maintained in a file storage and how the program reads the file to respond when its requested. This will create the clear way to avoid memory leakage in Node.js
const fs = require('fs'); const http = require('http'); const filename = './requestlogs.json'; const readRequests = () => { try { return fs.readFileSync(filename); } catch (e) { return '[]'; } }; const writeRequest = (req) => { const requests = JSON.parse(readRequests()); requests.push({ url: req.url, date: new Date() }); fs.writeFileSync(filename, JSON.stringify(requests)); }; const server = http.createServer((req, res) => { writeRequest(req); res.end(readRequests()); }); server.listen(3000); console.log('Server listening to port 3000. Press Ctrl+C to stop it.');
Understanding the process of how V8 garbage collection will work and following the better code optimization is the main key to application performance. Therefore when these memory usage improvement techniques are utilized in new version of Node.js and when better standards are followed-up then we can definitely experience the tremendous performance on our application.
Was it helpful?
Looking for more compelling tips to build strong and highly functional site in Node Js? No worries! you’re at the right the place, reach our highly skilled Node Js developers to build high performance sites.