Skip to content

feat(javascript): the Garbage Collection story, in 2D and 3D - #224

Merged
mnaimfaizy merged 1 commit into
mainfrom
feature/js-garbage-collection-story
Oct 14, 2026
Merged

mnaimfaizy merged 1 commit into
mainfrom
feature/js-garbage-collection-story

Conversation

@mnaimfaizy

Copy link
Copy Markdown
Owner

The story

Question: how does the collector decide what to free, and why can two objects that reference each other not keep each other alive?

A short program builds two parent-and-child pairs that point at each other, then sets one variable to null. Nine beats follow one collection:

  1. Two pairs, two cycles, each held by one variable.
  2. draft = null: the stack reference goes; the two objects still point at each other.
  3. The collector starts at the roots.
  4. It follows page and marks that object.
  5. The mark spreads to the second object.
  6. The reference back leads to an object already marked, so the search stops.
  7. Marking is done; the draft pair has no mark. The learner is asked to predict.
  8. The sweep reads marks, not references, and reclaims both draft objects.
  9. The program carries on with what was kept.

Spec: docs/stories/javascript/garbage-collection.md, approved 2026-10-13 with its eight decisions recorded.

What changes

  • Beat model and tests (garbageCollectionStory.ts). The tests prove the key claim from the data: the sweep reclaims exactly the objects no path from a root reaches, and each reclaimed object still had a reference pointing at it.
  • Shared 2D and 3D views draw a marked object: a MARKED tag and a heavier outline in the object's own colour. It is drawn only while a collection is in progress, so Playground traces look as before.
  • A mutual pair of references is kept apart: in 2D the return reference arcs over the top, in 3D each takes its own lane. Single references are drawn as before.
  • 3D: the root pulse plays only when a frame is in focus, and an object held from the stack keeps its label clear of that reference.
  • The Garbage Collection section: the old simulation is removed. It ignored the code in its editor, had no roots, and drew the young generation in a way the research contradicts. The story takes its place, with one line saying this is not all of V8's collector and one naming reference counting. Two unsupported claims in the prose are fixed.
  • Bridges: the Stack ↔ Heap story and this one point at each other, and "Try it in the Playground" opens the new example garbage-collection-story.
  • Quiz: two new JavaScript questions on cycles (q32, q33).
  • Research report: two paragraphs in section 6.3 on roots, cycles and reference counting. Both cited pages were read; two points that neither page states are marked as following from the algorithm.

Relation to the Playground

A trace of the same program reproduces beats 1 and 2, and a test confirms the two objects a trace marks unreachable are exactly the two the story's sweep reclaims. Beats 3 to 8 are authored: a run cannot observe marking or a sweep.

Checks

npx tsc -b, npm run lint and npm run build pass; three.js is not in the entry graph.

npm run test:run passed in full once on this branch (1,434 tests in 104 files). Later full runs on the same machine, which was busy with unrelated builds, had timeouts in PlaygroundApp.exercises, Sidebar, Header and Progress tests. Each of those files passes when run by itself. CI is the cleaner measure.

Checked in the browser: all nine beats in 2D with the right tags on each; beats 6 and 8 in 3D; a fresh 3D load stepped through every beat and switched back to 2D with no console errors; the link from the Stack ↔ Heap story.

Not checked in a browser

Reduced motion, the no-WebGL fallback and Hold view for this story; the Stack ↔ Heap story and Playground traces after the shared-view changes (covered by tests).

🤖 Generated with Claude Code

A nine-beat story of one collection: the collector starts at the roots,
marks what references lead to, stops at an object it has already marked,
and sweeps what has no mark. Two objects that still reference each other
are reclaimed together, because the sweep reads marks, not references.

The shared stack-and-heap views now draw a marked object (a MARKED tag
and a heavier outline, only while a collection is in progress) and keep
the two references of a mutual pair apart. The section's old simulation,
which ignored its own editor and had no roots, is removed.

Also: the story's program as a Playground example, two quiz questions on
cycles, and a passage on roots, cycles and reference counting in the
research report.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@mnaimfaizy
mnaimfaizy merged commit be93e30 into main Oct 14, 2026
9 checks passed
@mnaimfaizy
mnaimfaizy deleted the feature/js-garbage-collection-story branch October 14, 2026 05:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant