bi-04 — Analysis

Required invariants

  1. Wrapper identity is stable. document.body === document.body, and expandos survive a round trip through C++. This single requirement forces the unified heap.
  2. Wrappers are created lazily. A node has no JS object until script observes it — which is why a gratuitous querySelectorAll('*') costs more than the query.
  3. Mutation records, it does not recompute. A thousand DOM writes are not a thousand layouts; one interleaved geometry read makes them so.
  4. Author code never observes an inconsistent tree. Custom element reactions are queued; MutationObserver delivers on a microtask; synchronous mutation events were removed for exactly this reason.
  5. Style and layout use the flat tree. Not the node tree. Slot assignment does not change parentNode.
  6. Reachability is not sufficient for liveness. ActiveScriptWrappable keeps objects with pending activity alive; the ExecutionContext teardown clause stops that becoming a leak.

The lifetime failure modes

Leak shapeMechanismHow you find it
Detached subtreea JS reference holds a removed node and everything its listeners close overheap snapshot, retainer chain
Never-disconnected observerobserver holds target, target holds document scopeaudit disconnect() in cleanup
Long-lived Persistent<T>a root from non-GC code that is never droppedread the Trace() methods
Listener on a shared objectclosure retains the componentremove in cleanup — fw-02's lab

What the heap partitioning discloses

Node, CSSValue, and LayoutObject each get a dedicated typed space in Oilpan. That is a performance disclosure: those are the highest-volume allocations in a renderer. Your stylesheet allocates tooCSSValue earning its own space is the evidence, and it corrects the common model in which "the DOM" is the only thing that costs memory.

The coupling nobody documents

Oilpan schedules GCs through the message loop, at points where no objects are referenced from the native stack, so collection can be precise rather than conservative. The scheduler is therefore also a GC safepoint mechanism — a cross-subsystem constraint that appears in no document about either scheduling or garbage collection alone. Finding couplings like this is what reading two subsystems together buys you.