Garbage Collection (GC) in JavaScript: Memory Pressure and Jank

LowIntermediateJavascript
Preparing for interviews?

Use guided tracks for structured prep, then practice company-specific question sets when you want targeted interview coverage.

Quick Answer

Explain how JavaScript garbage collection works at a high level, why memory pressure can cause UI jank (GC pauses), and how to investigate it with Chrome DevTools (Performance + Memory panels). Include WeakMap/WeakRef use cases and common pitfalls.

Answer

Big idea

JavaScript is garbage-collected: you don’t free memory manually. But you do control which objects remain reachable. If your app allocates lots of short-lived objects or accidentally retains references, the GC has more work to do — and that can show up as jank (stutters) in the UI.

Concept

What it means

Why you care (frontend)

Reachability

If something is reachable from roots (global, closures, DOM refs), GC won't collect it

Leaks are usually "still referenced", not "GC failed"

Memory pressure

Heap grows → GC runs more often / more aggressively

Frequent GCs can compete with rendering

GC pauses

Some GC work stops the world briefly

Pauses can push frames over 16ms and hurt INP

GC is automatic, but your allocation patterns and references decide the workload.

Practical scenario

You render a feed and create new objects on every scroll (formatting strings, building derived arrays, cloning objects). The UI looks fine on a dev machine, but on mid-range devices you see stutters. Often the hidden cause is allocation churn: the GC runs repeatedly, causing small pauses that add up.

JAVASCRIPT
// Allocation-heavy pattern (creates new arrays/objects frequently)
function render(items) {
  const rows = items
    .filter(x => x.visible)
    .map(x => ({ id: x.id, label: `${x.name} (${x.count})` }));

  // ... render rows
}

// Lower-churn patterns:
// - avoid repeated cloning
// - memoize derived data
// - keep caches bounded (LRU)
// - reuse arrays where possible (carefully)
                  

How to investigate in Chrome DevTools

1) Performance panel: record a trace while reproducing jank.

  • Look for long tasks, layout thrash, and also GC activity markers.

2) Memory panel:

  • Take heap snapshots before/after repeating an interaction.
  • Use Retainers to see what keeps objects alive.
  • Use Allocation instrumentation to find hot allocation sites.

If memory keeps growing and never comes down after a "steady-state" interaction, you likely have a retention leak.

Common leak source

Why it retains

Fix pattern

Event listeners / subscriptions

Callback closures keep data reachable

Remove/unsubscribe on cleanup

Unbounded caches (Map, arrays)

No eviction → heap grows forever

Bounded cache (LRU/TTL) + key hygiene

Detached DOM nodes

JS references keep removed nodes alive

Don't store DOM nodes long-term; null references

Timers

Intervals keep closures alive

clearInterval/clearTimeout in cleanup

Most "memory leaks" are just references that never get released.

WeakMap / WeakRef: when they help

  • WeakMap keys are weakly held: if the key object becomes unreachable, the entry can be collected.
  • This is useful for memoization keyed by objects (DOM nodes, component instances) where you don't want your cache to keep them alive.

They are not a silver bullet: you still need to remove event listeners, bound caches, and avoid retaining large graphs in closures.

Pitfalls

  • Treating GC as a fix: "it will clean up" → not if you still reference it.
  • Allocating aggressively in hot paths (scroll, animation frames).
  • Using caches without eviction or with high-cardinality keys.
  • Profiling only in dev builds (prod code can behave differently).

Answer to land

"If the UI is janky after repeated interactions, I profile both CPU and memory. I look for allocation churn and GC markers in the Performance panel, then use heap snapshots and retainers to confirm what stays reachable. Fixes are usually: cleanup subscriptions/listeners, bound caches (LRU/TTL), and reduce allocations in hot paths."

Similar questions
Guides
36 / 61