Course contentsShow
← Node.js
Lesson 1696 of 1,98015. Logging, Observability, and MetricsFree lesson

Detecting Garbage Collection Pressure

Monitor GC frequency to identify code paths that create excessive short-lived objects.

In this lesson, you will learn how to identify when excessive object allocation is forcing the V8 engine to spend too much time on Garbage Collection (GC), causing performance "stutters."

Understanding GC Pressure

Even if your application isn't suffering from a classic memory leak—where memory usage climbs indefinitely—it can still suffer from GC Pressure. This happens when your code creates a massive volume of short-lived objects in the "Young Generation" heap. Because the heap fills up quickly, the GC must trigger frequent "Minor GC" cycles to reclaim space.

If your service processes thousands of requests per second, creating unnecessary intermediate objects (like deeply nested object clones or large temporary arrays) forces the CPU to spend more time cleaning up memory than executing your business logic. This manifests as increased event loop latency and erratic response times.

Monitoring GC via perf_hooks

To detect this, we monitor GC events using the perf_hooks module. By tracking the duration and frequency of GC cycles, we can flag code paths that are generating too much "garbage."

const { PerformanceObserver } = require('perf_hooks');

const obs = new PerformanceObserver((list) => {
  const entry = list.getEntries()[0];
  // 'major' indicates deep heap cleanup; 'minor' indicates young generation pressure
  if (entry.duration > 50) { // Flag GC pauses longer than 50ms
    console.warn(`High GC Pressure detected: ${entry.name} took ${entry.duration.toFixed(2)}ms`);
  }
});

obs.observe({ entryTypes: ['gc'] });

Identifying the Culprit

When you see a spike in frequency or duration of these events, look at your most frequent code paths. Common culprits include:

  1. Object Allocation in Loops: Creating new objects inside a high-frequency Array.map or forEach.
  2. Buffer Over-allocation: Allocating new buffers for every chunk of a data stream instead of using a pool.
  3. Deep Object Cloning: Using JSON.parse(JSON.stringify(obj)) for deep copies inside request handlers.

By correlating these GC metrics with your custom request telemetry, you can pinpoint exactly which endpoints are triggering the memory thrashing.

Key Takeaway: Monitoring the duration and frequency of GC cycles allows you to identify "allocator-heavy" code paths that degrade performance, even when total memory consumption remains stable.