javascriptcore-garbage-collector
JavaScriptCore's Garbage Collector (Riptide)
Riptide is non-moving, generational, parallel, mostly-concurrent, conservative-on-the-stack. Understanding those five words prevents most GC bugs in Bun.
The mental model
The heap is a graph. GC does a breadth-first search from roots → marks everything it reaches → everything unmarked is freed (lazily, on next allocation from that block). It does NOT compact or move objects — pointers stay stable for an object's lifetime.
Two collection modes:
- Eden GC: only scans newly-allocated objects + remembered set. Fast, frequent.
- Full GC: scans everything. Slower, rarer.
It runs concurrently. Marking happens on background threads while JS is executing; the mutator only stops at brief safepoints. visitChildren runs off the main thread, racing with your code.
How the VM gathers roots
Roots are not a hardcoded list — they are marking constraints registered with Heap::addMarkingConstraint() and run to fixpoint. The built-in set lives in Heap::addCoreConstraints() (vendor/WebKit/Source/JavaScriptCore/heap/Heap.cpp:2970):