Node.js
Advanced
63 helpful
1496 views

Fix Memory Leaks in Node.js Applications

Published Apr 14, 2025 Last updated Jun 16, 2025

Problem

Node.js application memory usage keeps growing over time, eventually causing the application to crash or become unresponsive.

Root Cause

Memory leaks in Node.js typically occur due to unclosed event listeners, retaining references to large objects, circular references, or improper cleanup of timers and streams.

Solution

Identify and fix common Node.js memory leak patterns:

Step 1: Monitor Memory Usage

// Add memory monitoring
function logMemoryUsage() {
    const used = process.memoryUsage();
    console.log('Memory Usage:');
    for (let key in used) {
        console.log(`${key}: ${Math.round(used[key] / 1024 / 1024 * 100) / 100} MB`);
    }
}

// Log every 30 seconds
setInterval(logMemoryUsage, 30000);

Step 2: Fix Event Listener Leaks

// ❌ Problem - event listeners not removed
function createUser(userId) {
    const user = new EventEmitter();

    // This listener is never removed
    user.on('update', handleUpdate);

    return user;
}

// ✅ Solution - properly remove listeners
function createUser(userId) {
    const user = new EventEmitter();

    function handleUpdate(data) {
        // Handle update
    }

    user.on('update', handleUpdate);

    // Cleanup function
    user.cleanup = () => {
        user.removeListener('update', handleUpdate);
        user.removeAllListeners();
    };

    return user;
}

Step 3: Fix Timer and Interval Leaks

// ❌ Problem - timers not cleared
function startPolling() {
    setInterval(() => {
        fetchData();
    }, 5000);
}

// ✅ Solution - clear timers properly
function startPolling() {
    const intervalId = setInterval(() => {
        fetchData();
    }, 5000);

    // Return cleanup function
    return () => clearInterval(intervalId);
}

// Usage
const stopPolling = startPolling();
// Later, when no longer needed:
stopPolling();

Step 4: Handle Stream Cleanup

// ❌ Problem - streams not properly closed
function processFile(filename) {
    const readStream = fs.createReadStream(filename);
    const writeStream = fs.createWriteStream('output.txt');

    readStream.pipe(writeStream);
    // Streams might not be properly closed
}

// ✅ Solution - ensure proper cleanup
function processFile(filename) {
    return new Promise((resolve, reject) => {
        const readStream = fs.createReadStream(filename);
        const writeStream = fs.createWriteStream('output.txt');

        readStream.on('error', (err) => {
            cleanup();
            reject(err);
        });

        writeStream.on('error', (err) => {
            cleanup();
            reject(err);
        });

        writeStream.on('finish', () => {
            cleanup();
            resolve();
        });

        function cleanup() {
            readStream.destroy();
            writeStream.destroy();
        }

        readStream.pipe(writeStream);
    });
}

Step 5: Use Memory Profiling Tools

# Install clinic.js for memory profiling
npm install -g clinic

# Profile your application
clinic doctor -- node app.js

# Or use built-in Node.js inspector
node --inspect app.js
# Then open Chrome DevTools for memory profiling
Back to Solutions
1