Compile Ready
Module 3 · Scope & Closures

Closures & Memory

Advanced7m read3m practice10m total
ClosuresMemoryGarbage CollectionLeaks

Introduction

Closures are not just a syntax feature; they affect memory. If a function closes over a variable and that function is still reachable, the captured variable must remain reachable too.

That is usually exactly what you want — a counter remembering its count — but it can become a memory leak when long-lived callbacks accidentally retain large objects.

Why This Matters

Senior JavaScript interviews often move from "what is a closure?" to "what does it keep alive?". Understanding closure memory helps you debug leaks caused by event handlers, timers, caches, and stale callbacks in long-running applications.

Theory

Closures keep reachable bindings alive

JavaScript garbage collection is based on reachability. If an object can be reached from roots such as the global object, the call stack, active timers, event listeners, or module state, it cannot be collected.

A reachable closure points to its captured lexical environment. Any captured variable that can still be used by the closure must stay alive. Engines can optimise details, but the semantic rule is simple: if reachable code can observe it later, it cannot disappear.

A closure does not always mean a leak

Most closures are short-lived and cheap. A closure becomes a leak risk when it is held for longer than intended and captures more data than necessary. Common examples:

Long-lived holderCaptured by closureLeak risk
Event listenerlarge object or component statelistener not removed
setInterval callbackold data snapshotinterval not cleared
Unbounded memoization cachemany resultscache grows forever
Global array of callbacksrequest/user objectscallbacks never removed

When is closure memory freed?

The captured environment can be collected when no reachable closure can use it anymore. Practically, that means you remove event listeners, clear timers, delete callbacks from registries, or let the returned function itself become unreachable.

You can also release heavy captured data earlier by assigning the captured variable to null when it is no longer needed. The closure may remain, but it no longer retains the large object through that variable.

Avoid overclaiming

In interviews, avoid saying "closures keep the whole stack frame forever." The accurate model is: closures keep the necessary lexical bindings reachable. Engines may optimise unused variables, but observable captured values must behave as if they remain available.

Visual Diagrams

How a long-lived closure can retain memory
GC roots
  |
  v
active interval / listener
  |
  v
callback function (closure)
  | hidden lexical link
  v
captured environment
  |
  v
large object or stale state

Clear the interval/listener or clear the captured reference to allow collection.

Garbage collection follows reachability. A reachable callback can keep its captured data alive.

Code Examples

A timer closure retains what it uses

The interval callback keeps items reachable until the interval is cleared or the callback becomes unreachable.

Loading…

Release a heavy captured value explicitly

If the closure must remain alive but no longer needs the heavy data, clear the captured reference.

Loading…

Output Prediction

Predict the output #1

javascript
1function makeReader() {
2 let data = ['large', 'payload'];
3
4 return {
5 read: function () {
6 return data ? data.length : 0;
7 },
8 release: function () {
9 data = null;
10 }
11 };
12}
13
14const reader = makeReader();
15console.log(reader.read());
16reader.release();
17console.log(reader.read());

Interview Questions

1Do closures cause memory leaks?

Closures do not inherently cause leaks. They keep captured variables alive while the closure is reachable, which is correct behavior. A leak happens when a closure is unintentionally kept alive for too long — for example by an uncleared interval, an event listener that was not removed, or an unbounded cache — and it retains large data that should have been released.

Asked at:NetflixMetaGoogleMicrosoft

Follow-ups

  • How would you fix an event-listener leak?
  • Can a captured variable be cleared while the closure remains?
2When can the memory captured by a closure be garbage-collected?

When it is no longer reachable. If no reachable function can access the captured environment, the environment can be collected. You can make that happen by dropping references to the closure, removing listeners, clearing timers, deleting callbacks from registries, or clearing captured references such as setting a large object variable to null.

Quiz

1. A closure captures a large array. When can that array be garbage-collected?

2. Which pattern is most likely to leak memory?

Summary

  • Reachable closures keep their captured lexical bindings reachable.
  • Closures are not leaks by default; leaks come from closures that live longer than intended.
  • Timers, listeners, registries, and unbounded caches are common retention sources.
  • Free memory by removing holders, dropping closure references, bounding caches, or clearing captured heavy values.