How to Detect and Fix Node.js Memory Leaks: V8 GC, Tools, and Code Samples

This article explains why Node.js applications can suffer memory leaks due to V8 garbage‑collection limits, describes V8 memory regions and GC types, and provides practical commands, monitoring tools, and a reproducible code example to identify and resolve leaks.

Tencent IMWeb Frontend Team
Tencent IMWeb Frontend Team
Tencent IMWeb Frontend Team
How to Detect and Fix Node.js Memory Leaks: V8 GC, Tools, and Code Samples

During server‑side rendering, React can leak memory when NODE_ENV is not set to production, as reported in GitHub issue #7406 . Because Node.js runs on the V8 engine, understanding V8’s memory management is essential for diagnosing such leaks.

V8 Memory Limits

Node inherits V8’s memory limits: on 64‑bit systems the old generation is about 1.4 GB, the new generation about 32 MB (half on 32‑bit). Exceeding these limits can cause the process to exit.

Reason: V8 performs stop‑the‑world garbage collection, pausing JavaScript execution until the GC finishes. A full GC on a 1.5 GB heap can take >50 ms, while a non‑incremental GC may exceed 1 second.

You can raise the limits with node --max-old-space-size=xxxx (MB) and node --max-new-space-size=xxxx (KB).

V8 Heap Layout

The heap consists of several regions:

New generation: small, frequent GC.

Old generation pointer space: stores objects that may reference others.

Old generation data space: stores raw data objects without pointers.

Large object space: holds objects too big to move during GC.

Code space: contains JIT‑compiled code, the only executable memory region.

Cell, property‑cell, and map spaces: store uniform‑size elements.

GC Types

Incremental GC collects garbage while scanning memory and clears it at the end of the cycle. Non‑incremental GC clears garbage immediately when found.

GC runs on the new generation, old generation pointer space, and old generation data space. Objects start in the new generation; if they survive, they are promoted to the old generation where less frequent, longer incremental GC occurs.

When Do Leaks Occur?

Common leak sources include:

Unreleased caches.

Queues that are not consumed promptly.

Scopes that are never released.

Analyzing Memory Usage

Check V8 memory (bytes):

process.memoryUsage();
{
    rss: 47038464,
    heapTotal: 34264656,
    heapUsed: 2052866
}

Check system memory (bytes):

os.totalmem()
os.freemem()

View GC logs:

node --trace_gc -e "var a = []; for (var i = 0; i < 1000000; i++) { a.push(new Array(100)); }" >> gc.log

node --prof   // outputs performance log

Monitoring tools:

v8‑profiler – heap snapshots and CPU profiling.

node‑heapdump – capture V8 heap snapshots.

node‑mtrace – stack usage analysis.

node‑memwatch – monitor GC events.

node‑memwatch example:

memwatch.on('stats', function(info) {
    console.log(info);
});
memwatch.on('leak', function(info) {
    console.log(info);
});

Typical stats event payload:

{
    "num_full_gc": 17,
    "num_inc_gc": 8,
    "heap_compactions": 8,
    "estimated_base": 2592568,
    "current_base": 2592568,
    "min": 2499912,
    "max": 2592568,
    "usage_trend": 0
}
A leak event is emitted if memory is not reclaimed after five consecutive GCs.
{
    start: Fri, 29 Jun 2012 14:12:13 GMT,
    end: Fri, 29 Jun 2012 14:12:33 GMT,
    growth: 67984,
    reason: 'heap growth over 5 consecutive GCs (20s) - 11.67 mb/hr'
}

Practical Example

The following script deliberately creates a memory leak by continuously pushing objects into an array and periodically writing heap snapshots.

// app.js
var app = require('express')();
var http = require('http').Server(app);
var heapdump = require('heapdump');

var leakobjs = [];
function LeakClass() {
    this.x = 1;
}

app.get('/', function(req, res) {
    console.log('get /');
    for (var i = 0; i < 1000; i++) {
        leakobjs.push(new LeakClass());
    }
    res.send('<h1>Hello world</h1>');
});

setInterval(function() {
    heapdump.writeSnapshot('./' + Date.now() + '.heapsnapshot');
}, 3000);

http.listen(3000, function() {
    console.log('listening on port 3000');
});

Running this app and repeatedly refreshing http://localhost:3000 shows the heap snapshot size growing continuously, confirming a leak. Chrome DevTools can compare snapshots to pinpoint the growing LeakClass instances.

Summary

Use memwatch or periodic process.memoryUsage() reporting with alerts to detect leaks.

When a leak is suspected, generate heap snapshots with node‑heapdump and analyze them in Chrome Profiles or with v8‑profiler.

Adjust monitoring frequency to avoid excessive CPU usage, and be aware of false positives caused by short‑term memory spikes.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

BackendPerformance Monitoringmemory leakV8gcnodejs
Tencent IMWeb Frontend Team
Written by

Tencent IMWeb Frontend Team

IMWeb Frontend Community gathering frontend development enthusiasts. Follow us for refined live courses by top experts, cutting‑edge technical posts, and to sharpen your frontend skills.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.