Course contentsShow
← Node.js
Lesson 1316 of 1,98012. Caching Strategies and Application SpeedFree lesson

Memory Leak Mitigation in Long-Lived Cache Objects

You will identify and resolve patterns that cause unbounded cache growth leading to OOM errors.

Memory Leak Mitigation in Long-Lived Cache Objects

In this lesson, you will learn how to identify and resolve "unbounded growth" patterns that turn long-lived cache objects into ticking time bombs for OutOfMemory (OOM) errors.

When we store data in a persistent JavaScript object (like a global cache map), we often fall into the trap of assuming memory is infinite. If your application pushes new data into a cache without a mechanism to prune old entries, your heap will expand indefinitely until the Node.js process crashes. This is a classic "memory leak" where the garbage collector cannot reclaim memory because the object is still reachable through your cache reference.

Identifying the Leak

Consider this common anti-pattern:

const globalCache = {};

function addToCache(key, value) {
  // Unbounded growth: this grows forever until OOM
  globalCache[key] = value;
}

Even if individual items are small, a long-lived application processing thousands of requests will eventually exhaust the heap limit. To mitigate this, we must transition from static storage to bounded storage.

Implementing Eviction Policies

The goal is to ensure the cache size remains predictable. Instead of a simple object, use a structure that respects memory limits. If you must use a standard Map, you should wrap it with a TTL (Time-to-Live) strategy or a strict size limit.

A simple mitigation strategy is to track the number of keys and enforce an eviction policy:

const MAX_ENTRIES = 1000;
const cache = new Map();

function safeCache(key, value) {
  if (cache.size >= MAX_ENTRIES) {
    // Delete the oldest entry (the first one inserted)
    const firstKey = cache.keys().next().value;
    cache.delete(firstKey);
  }
  cache.set(key, value);
}

By manually deleting the oldest entry when the limit is reached, you guarantee that the cache never consumes more memory than your defined budget. In professional environments, you would pair this with TTL-based expiration to ensure stale data doesn't persist, preventing both memory bloat and "stale-data" bugs.

Key Takeaway: Never create a cache that grows without bound; always enforce a maximum capacity or time-based eviction strategy to keep your heap stable.