Files
Miguel Angel Simon Sierra 3ca8f1018e fix(studio): release the previous project's render scopes on switch
Ten project-switch cycles retained 0.24 MB of JS heap per cycle, monotonic
and unbounded. Two causes, both in how memoized callbacks keep render scopes
alive.

A `useCallback` whose deps changed is a NEW closure in the current render's
scope; every callback whose deps did NOT change is the closure from an earlier
render, stored into that same fresh scope. That one edge chains render scope N
to render scope N-1. A project switch changes projectId, activeCompPath and
timelineElements at once, so each switch added a link — and each link pinned
that render's lint result (~240 findings) and its element snapshot plus the
cached index built from it, for the life of the session.

`useLintModal` and `useDomSelection` now build their callbacks once and read
render-scoped values through a ref, so no stale closure lands in a fresh scope.
`groupFindings` moves to module scope and takes the findings as an argument
instead of closing over them.

Separately, the composition-source map was pinning a whole document per open:
V8 represents a substring of 13+ characters as a SlicedString that keeps its
parent alive, so a handful of `compositions/*.html` paths cut out of a 36 KB
`index.html` held that document as long as the map lived.

Measured on two generated fixtures, forced GC between samples, production
React, same method before and after:

  cycles  heap/cycle before  after
  11      0.237 MB           0.100 MB
  21      0.202 MB           0.061 MB

Nodes (+0) and listeners (+0) were already flat once the probe stopped holding
puppeteer ElementHandles, which pin an element and its whole ancestor chain
through a DevTools global handle and read as detached-DOM retention.

The remaining slope is V8 tier-up, not retention: code space grows 81 KB per
open over the first eight opens and 22 KB over the next eight, and the heap
slope decays with it (0.100 -> 0.061) where before it did not (0.237 -> 0.202).
2026-08-03 22:05:35 -07:00
..
2026-08-02 21:57:19 -07:00
2026-08-02 21:57:19 -07:00
2026-08-02 21:57:19 -07:00