Overview & generational GC
Orinoco is the project name for V8's garbage collector. Its entire design is organized around one goal that matters for performance: reclaim memory without long main-thread pauses. It achieves that with four ideas working together — generational, parallel, concurrent, and incremental collection. This page sets up the model; the rest of the section drills into each collector.
::: info Ubiquitous language Orinoco: V8's GC. Young/old generation: the generational split. Scavenge: a cheap young-generation collection. Mark-Compact: a full old-generation collection. Parallel = many threads during a pause; concurrent = work alongside running JS; incremental = work split into small steps. :::
The generational hypothesis
The empirical observation that drives everything: most objects die young. A huge fraction of allocations (closures, temporary arrays, intermediate strings) become garbage almost immediately; the few that survive tend to live a long time.
So V8 splits the heap by age:
The young generation (a small "new space") is collected often and cheaply. Because most of it is dead, collection touches little.
Survivors are promoted to the old generation, collected rarely with a more expensive algorithm.
This means the common case — short-lived garbage — is handled by the cheap collector, and the expensive collector runs seldom. It is the single biggest structural win in the GC.
The spaces
V8's heap is divided into spaces:
enum SemiSpaceId { kFromSpace = 0, kToSpace = 1 };
// A SemiSpace is a contiguous chunk of memory holding page-like memory chunks.
class SemiSpace final : public Space { … };
— src/heap/new-spaces.h#L35-L43
New space (young) — two equal semispaces (from/to) for the Scavenger's copying algorithm. Small (megabytes).
Old space — paged, free-list managed, collected by Mark-Compact:
class OldSpace : public PagedSpace { explicit OldSpace(Heap* heap) : PagedSpace(heap, OLD_SPACE, NOT_EXECUTABLE, FreeList::CreateFreeList(), CompactionSpaceKind::kNone) {} };Plus specialized spaces: large-object, code, read-only, and shared spaces. Objects are aligned to the tagged size, which is what frees the low bits for tagging:
constexpr int kObjectAlignmentBits = kTaggedSizeLog2; constexpr intptr_t kObjectAlignment = 1 << kObjectAlignmentBits;
Two collectors
| Scavenger (minor GC) | Mark-Compact (major GC) | |
|---|---|---|
| Collects | young generation | whole heap (old + young) |
| Algorithm | parallel semispace copying (Cheney) | mark, sweep, compact |
| Frequency | often | rarely |
| Typical pause | sub-millisecond–few ms | longer, but mostly off-thread |
Keeping pauses short: the three concurrency levers
A full collection that stopped the world for its entire duration would freeze the UI. Orinoco avoids that with:
Parallel — within a pause, spread the work across many helper threads (parallel scavenge, parallel marking/evacuation).
Concurrent — do most marking on background threads while JavaScript keeps running, so only a short final pause remains.
Incremental — split marking into small steps interleaved with execution, each capped to a few milliseconds, instead of one big stop.
Together these turn what would be a ~100 ms stop-the-world pause into many tiny steps plus a short atomic finish. The price JS pays for concurrent/incremental correctness is the write barrier.
The tax JavaScript pays: write barriers
Generational and concurrent collection both need to know about certain pointer stores (old→young pointers; stores during marking). So every pointer write in JS runs a tiny write barrier that records the interesting ones. It is the cost that makes cheap young-gen collection and concurrent marking possible — a deliberate trade of a little per-store work for much shorter pauses.
A note on allocation
Young-generation allocation is a pointer bump in a thread-local buffer — about as cheap as allocation can be. We cover this and promotion in the Scavenger page.
Read next
Scavenger — the young-generation copying collector.
Mark-Compact — the old-generation collector.
Concurrent & incremental marking — short pauses.
Write barriers — the invariant-keeping tax.