Skip to content
Advanced10 min study

Memory management

Reason about reachability, garbage collection, retained objects, weak collections, and evidence-driven leak diagnosis.

Question progress0 / 10 completed
Start the lesson
Memory management visual explanation

WHAT YOU WILL BE ABLE TO DO

Learning outcomes

  • Explain memory management in plain language.
  • Connect the behavior to the underlying browser or framework model.
  • Implement the core pattern and reason through edge cases.
  • Answer common follow-ups without relying on memorized phrases.

01Overview

JavaScript engines use mark-and-sweep garbage collection: starting from roots (globals, the current stack), the engine marks everything reachable and frees everything else. Memory leaks in JS are really unintentional reachability — something keeps a reference alive longer than intended.

Think of it like this: garbage collection is a landlord who only evicts tenants nobody can reach anymore — if there's still a working phone number, a forwarding address, or literally anyone holding onto a way to contact that tenant, the landlord leaves them alone, even if you personally think they should be gone.

02Mental model

  • Detached DOM nodes: a removed element is still reachable (and unreleasable) if a variable or closure still references it.
  • Forgotten timers/intervals/listeners: a setInterval or addEventListener that's never cleared keeps its closure — and everything it captured — alive indefinitely.
  • Unbounded caches: a Map or object used as a cache with no eviction policy grows forever.

03Examples

JavaScript
function attach(el) {  const bigData = new Array(1_000_000).fill('x');  const handler = () => console.log(bigData.length);  el.addEventListener('click', handler);  return () => el.removeEventListener('click', handler); // call this on cleanup}

04Check understanding

A single-page app's memory grows on every route change even though components unmount. What's the likely cause?

A listener, timer, or subscription set up per route isn't being torn down in the corresponding cleanup, so each mount adds another live closure the garbage collector can't reclaim.

How to say it out loud: "JavaScript engines use mark-and-sweep garbage collection: starting from roots like global variables and the current call stack, the engine marks everything reachable and frees everything that isn't. So a memory leak in JavaScript isn't really about memory being handled wrong — it's about something unintentionally keeping a reference alive longer than it should. The most common real culprits are forgotten event listeners or intervals that were never cleaned up, detached DOM nodes still referenced by a variable or closure, and unbounded caches that just keep growing with no eviction policy."

DDConcept deep dives

Deep dive 1

Reachability, not reference counting, is the useful model

Garbage collectors begin from roots and trace reachable values. An unreachable cycle can be collected, while one unintended path from a global cache or active listener can retain a large graph. Eligibility does not mean immediate collection; engines schedule and optimize collection based on their own heuristics.

  • High reserved heap is not proof of a leak.
  • A leak is unwanted continued reachability across the application's expected lifecycle.
  • Finalization timing must never be required for core program correctness.

Deep dive 2

Common leaks are missing ownership boundaries

Timers, event listeners, observers, subscriptions, unresolved work, detached DOM references, and unbounded collections all need a clear owner and release condition. Framework unmounting removes managed DOM, but it cannot automatically clean external resources created without returning or invoking their teardown.

  • Register and release resources in paired lifecycle code.
  • Bound caches by count, cost, or expiry instead of assuming eventual collection.
  • Abort obsolete work to release closures and reduce wasted computation.

Deep dive 3

Heap evidence beats guessing

Design a repeatable interaction cycle, allow or request garbage collection in tooling, compare snapshots, and find object types whose retained counts grow after every cycle. A retaining-path view shows the chain back to a root. Fix the earliest unintended owner and repeat the identical experiment to prove the graph is released.

  • Allocation timelines reveal which interaction created growing objects.
  • Detached nodes are clues, not automatic proof of a leak.
  • WeakMap is useful for metadata keyed by object lifetime, but it does not repair other strong references.

QAInterview questions and model answers

Attempt each answer aloud before opening it. The model answer shows the depth and precision expected in an interview; it is not a script to memorize.

Intermediate · Conceptual · 1 min · Question 1How does JavaScript garbage collection decide what to reclaim?Open model answer

Model answer

Modern collectors primarily determine reachability from roots such as active execution state and host references. Objects that cannot be reached are eligible for collection even if they participate in cycles. Collection timing is intentionally nondeterministic.

Open question page →
Intermediate · Conceptual · 1 min · Question 2What is a memory leak in garbage-collected JavaScript?Open model answer

Model answer

It is memory that remains reachable even though the application no longer needs it. Common causes include unbounded caches, forgotten listeners or timers, retained detached DOM nodes, observers, and closures captured by long-lived owners.

Open question page →
Advanced · Coding · 1 min · Question 3Why do WeakMap keys not prevent collection?Open model answer

Model answer

A WeakMap does not keep its object keys strongly reachable. When a key has no other strong path from a root, its entry may disappear. Weak collections are non-enumerable because collection timing cannot become observable.

JavaScript
const meta = new WeakMap();let node = document.createElement('div');meta.set(node, { renderedAt: Date.now() });
node = null; // nothing else references the div ->             // the div AND its WeakMap entry become collectible
Open question page →
Intermediate · Conceptual · 1 min · Question 4How would you diagnose a browser memory leak?Open model answer

Model answer

Reproduce a stable interaction cycle, record heap allocation or compare snapshots, trigger collection where tooling permits, and inspect retaining paths for object types whose counts keep growing. Fix the ownership path and repeat the same experiment.

Open question page →
Intermediate · Coding · 1 min · Question 5What is a detached DOM tree?Open model answer

Model answer

It is a DOM subtree removed from the document but still reachable from JavaScript, perhaps through a listener, closure, cache, or framework reference. Being detached is not itself a leak; continued unintended reachability is.

JavaScript
const cache = [];function render() {  const el = document.createElement('div');  cache.push(el);           // keeps every `el` alive forever  document.body.append(el);  el.remove();              // detached from the document, still in `cache`}
Open question page →
Intermediate · Conceptual · 1 min · Question 6Should cleanup set every local variable to null?Open model answer

Model answer

No. Locals naturally become unreachable when their environment is no longer retained. Cleanup should release long-lived ownership—unsubscribe, disconnect observers, clear timers, abort work, and bound caches—rather than ritualistically nulling short-lived variables.

Open question page →
Advanced · Conceptual · 1 min · Question 7What is generational garbage collection?Open model answer

Model answer

It organizes objects by observed lifetime so short-lived values can be collected frequently while older survivors are scanned differently. Exact strategies remain engine implementation details.

Open question page →
Advanced · Conceptual · 1 min · Question 8Why are WeakMap entries not enumerable?Open model answer

Model answer

Enumeration would expose whether garbage collection has occurred, making nondeterministic collection timing observable and preventing important implementation freedom.

Open question page →
Advanced · Conceptual · 1 min · Question 9Can an unresolved promise leak forever?Open model answer

Model answer

A promise and attached handlers are collectible when nothing reachable refers to them. It becomes a leak when a long-lived owner, pending host operation, or captured resource retains the chain.

Open question page →
Advanced · Conceptual · 1 min · Question 10What is the purpose of FinalizationRegistry?Open model answer

Model answer

It can schedule best-effort cleanup notifications after collection, but timing and execution are not guaranteed. Core resource correctness must use explicit disposal instead.

Open question page →

SCScenario questions

Scenario 1

A single-page dashboard grows by 20 MB after every route visit. Describe a reliable investigation.

  1. Automate repeated navigation so every sample performs the same work.
  2. Compare heap snapshots after garbage collection.
  3. Group growing constructors and inspect their retaining paths.
  4. Audit route cleanup for subscriptions, observers, timers, and caches.
  5. Verify the plateau after the fix.
Reveal worked answer

I would not diagnose from one high memory number because collectors reserve heap. Repeated route cycles plus post-GC snapshots reveal monotonic retention. The retaining path identifies the real owner—often a global subscriber, observer, timer, or cache. After cleanup I expect object counts to return near baseline and memory to plateau across cycles.

Verify and go deeper