HOW-TO · DEV

How to debug memory leaks in a Node.js application using AI-powered profiling analysis

advanced30 minBy Fredoline Eruo
Target environment
Ubuntu 24.04 · Ollama 0.4.x
PREREQUISITES

Node.js application with a suspected memory leak, heap snapshot tool (Chrome DevTools or node --inspect), AI assistant with access to source code

What this does

Memory leaks in Node.js applications manifest as gradually increasing RSS (Resident Set Size) memory usage over time, eventually leading to slowdowns or crashes. This guide uses the V8 heap snapshot feature combined with an AI assistant to identify objects that are retained unexpectedly and trace them back to the code that holds references to them. The process involves capturing heap snapshots at two points in time, comparing them for growth, and using the AI to analyze the retained object graph.

Steps

  1. Start the Node.js application with the --inspect flag to enable the V8 profiler:
node --inspect server.js
  1. Open Chrome and navigate to chrome://inspect. Select the running Node.js target and open the Memory tab in DevTools.

  2. Take a baseline heap snapshot immediately after the application starts and is in an idle state (no active requests). Click Take snapshot and wait for the snapshot to load.

  3. Exercise the application by performing the workload that triggers the suspected leak, such as repeatedly calling a specific API endpoint or running a long-lived background job.

  4. Take a second heap snapshot after the workload completes. Label it clearly (e.g., "After 100 requests").

  5. In DevTools, switch to the Comparison view and select the baseline snapshot as the reference. This view shows the change in object counts and memory footprint between the two snapshots.

  6. Identify the largest retainers by looking at the "Delta" column. Objects with large positive delta counts (especially strings, arrays, or closures) are the most likely leak sources.

  7. Copy the top five entries from the Comparison view into the AI assistant along with the relevant source file names.

  8. Ask the AI to identify which code paths in the source files are creating or retaining these object types. Include the heap snapshot excerpt in the query.

  9. Apply the recommended fixes (such as removing event listeners, clearing caches, or nullifying closures) and repeat the exercise. Compare the delta between snapshots to confirm the leak is reduced or eliminated.

Verification

Run the workload a second time against the fixed application. The delta in the Comparison view between two consecutive snapshots should show no statistically significant growth for the previously flagged object types. Memory usage as reported by process.memoryUsage() should stabilize rather than grow monotonically.

Common failures

  • Taking snapshots too early in the application lifecycle: Heap snapshots taken during startup show allocations that are part of normal initialization. Always compare snapshots taken at the same application state (e.g., after handling the same number of requests) rather than comparing startup to a busy state.
  • Misreading retained size vs. shallow size: The "Retained Size" column shows the total memory freed if the object and all its children are collected. The "Shallow Size" shows only the object's own memory. Focusing on shallow size can miss the actual memory impact of a retaining path.
  • AI misidentifying framework internals as leaks: Node.js frameworks and the runtime itself allocate objects that grow over time by design (e.g., the V8 optimizer, connection pool). Instruct the AI to exclude objects from node_modules and internal V8 namespaces from the analysis.
  • Fixes that only delay the leak: Setting a large interval to periodically call the garbage collector (global.gc()) masks the underlying cause by forcing frequent collections. Fix the actual reference chain rather than relying on forced garbage collection in production.
  • Heap snapshot file too large to upload to the AI: For production-scale applications, heap snapshots can be hundreds of megabytes. Filter the snapshot to show only the top 20 retainers by retained size before uploading to the AI assistant.

Related guides