V8pedia

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) {}
    };
    

    src/heap/paged-spaces.h#L444-L450

  • 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;
    

    src/common/globals.h#L1045-L1046

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:

  1. Parallel — within a pause, spread the work across many helper threads (parallel scavenge, parallel marking/evacuation).

  2. Concurrent — do most marking on background threads while JavaScript keeps running, so only a short final pause remains.

  3. 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.