In this chapter
We'll separate two ideas people mix up — scope (where a name can be seen) and lifetime (how long the data exists) — see how a closure keeps data alive, and look at the four sections every process's memory is divided into: code, data, stack and heap.
The Problem in Real Life
Anna points at the timer line: setTimeout(() => releaseSeat(seatId), HOLD_DURATION_MS). "seatId is a local variable. It's only visible inside holdSeat. When holdSeat ends, its stack tray is gone. So how can the timer still use seatId ten minutes later?"
John nods. "Because you've just mixed up two different questions: where can a name be seen, and how long does the data live. They're not the same."
Scope is about who can see a name. Lifetime is about how long the thing behind it exists.
John
Where a Name Can Be Seen vs. How Long the Data Lives
Two ideas, one word
People say "the variable is gone" — but the name and the data behind it can have different lives.
Functions can carry data
A function created inside another function can keep that function's data alive.
A process has a layout
Every running program divides its memory into the same four sections.
Lifetime, Scope and How a Process Uses Memory
The hotel guest analogy: think of a guest staying at a hotel. Scope is who can see the guest's name — say, only staff on the third floor can see the name card on the door. Lifetime is how long the guest actually stays in the hotel. These are different: a guest can stay for a week even though only the third-floor staff can see their name card.
In code, scope (Act 07) is where in the program a variable's name can be used. Lifetime is how long the data it refers to exists in memory. For a simple local number, they match: it's visible inside the function and it disappears when the function ends. But for data in the heap, lifetime is decided by reachability (last chapter), not by scope.
- Closures — a function that packs a suitcase: when you create a function inside another function, the inner function "packs a suitcase" with any outer variables it uses, and takes it along. This is called a closure. The timer's little function
() => releaseSeat(seatId)packedseatIdin its suitcase. Even afterholdSeatends and its tray is gone, the suitcase lives on in the heap, together with the inner function, for as long as the inner function itself is reachable. - Why closures matter for leaks: a closure keeps everything in its suitcase alive. If a long-lived structure — like the
timersmap — keeps holding the timer, it keeps the timer's function, and the function keeps its suitcase. A small closure is harmless. A closure that packed a large object, kept forever, is a leak.
| Feature | Scope | Lifetime |
|---|---|---|
| Question it answers | Where can this name be used? | How long does the data exist? |
| Hotel version | Who can see the guest's name card | How long the guest stays |
| Decided by | Where the variable is written in the code | Stack: until the function returns; heap: while reachable |
| Example | seatId is visible only inside holdSeat | seatId lives on inside the timer's closure |
| Thing | Lives in | Kept alive by |
|---|---|---|
| timers map | Created at startup, lives all day | Always reachable (a global) |
| Each timer | Heap | The timers map |
| Each timer's function | Heap | The timer |
| Its suitcase (seatId, and more) | Heap | The closure |
| Result | 300,000 holds a day, never removed | Memory climbs until the 3 AM crash |
The four sections of a process's memory
Stack
function call trays — grows downwards
Free space
room for the stack and heap to grow
Heap
objects, arrays, closures — grows upwards
Data section
global and static variables, live all the time
Code (text) section
the program's instructions — read-only
function makeGreeter(name) {// the inner function uses `name` — it packs it in its suitcasereturn () => console.log("Hello, " + name);}const greetAnna = makeGreeter("Anna");// makeGreeter has finished; its stack tray is gone...greetAnna(); // ...but this still prints "Hello, Anna" — the closure kept `name` alive
The timer in holdSeat works exactly the same way: its function keeps seatId alive for as long as the timer is reachable.
How a process uses memory — four sections: when the operating system starts a program as a process (Act 04 and Act 05), it gives it its own virtual address space and divides it into four main sections. Think of a building with four floors, each with a job.
The code section (also called the text section) — the program's instructions, the recipe itself. Read-only, so the program can't accidentally change its own code. The data section — global and static variables that exist for the program's whole life, created at the start and kept until the end, like the timers map. The stack — the pile of trays for function calls, usually growing from the top of the address space downwards. The heap — the warehouse for dynamically allocated objects, usually growing upwards. The free space between the stack and the heap gives both room to grow.
Now the whole picture of the leak fits on one page. The timers map lives for the process's entire life (data section or heap, always reachable). Each hold adds a timer to it. Each timer holds a closure. Each closure holds its suitcase. Nothing is ever removed from the map — even after the seat is paid for or released. So every hold since the last restart is still in the heap. The memory graph climbs all day, and at 3 AM, when the nightly sales report runs and needs a burst of extra memory, the heap hits its limit and the process crashes.
Key Takeaway
Scope is where a name can be seen; lifetime is how long the data exists. Heap data lives as long as it's reachable, so a closure — a function that packs a suitcase of outer variables — can keep data alive long after the outer function ended. A process's memory has four sections: code (instructions), data (globals), stack (function calls) and heap (dynamic objects).
Why This Matters
Mixing up scope and lifetime is behind some of the most confusing bugs in modern code — data that should be gone but isn't, or closures that quietly hold on to huge objects. And the four-section picture of a process explains error messages you'll meet for years: stack overflow, heap out of memory, segmentation fault. It's the map Anna needed to see the whole leak at once.
Anna can now explain the 3 AM crash from top to bottom. Time to fix it — and to learn the other classic memory bugs, so she can recognise them on sight.
