Tabs: release detached Mail views after Tab switches #1375

Open
opened 2026-10-07 15:02:26 +00:00 by kayg · 0 comments
Owner

Found in the production Tab-switching storm for #1338. Related: #1338 and #1233.

Three 120-second storms on one Chromium page left detached Mail <main class="mail-view"> nodes after forced GC. In the VM heap snapshots, detached Mail roots grew from 9 after storm 1 to 28 after storm 3 without CPU throttling, and from 5 to 15 with 4× CPU throttling. The native retaining path is:

(GC roots) → Global handles → NativeContext → Window.fetch → module context → SourceTextModule → Cell → #s.reactions[] → reaction.fn → closure context → detached Mail <main>

The production snapshot keeps the Svelte callback unnamed, so it cannot map the final closure to a source function. The retained DOM identifies MailView in apps/web/src/lib/mail/MailView.svelte, mounted by apps/web/src/routes/mail/+page.svelte. Review the component effects and onDestroy teardown (MailView.svelte around line 958) and add a repeated Tab-switch lifetime regression.

The same run measured 758/796 requests while Mail was selected, with max in-flight counts 9/8 and 7/25 aborted. The reader prefetch worker in MailView.svelte runs four jobs, each requesting a thread and message. onDestroy aborts the shared controller, but does not call clearQueuedReaderPrefetch; check whether queued jobs and Svelte reactions can retain departed views.

Heap snapshots and traces are local ignored artifacts: artifacts/tabstorm-1338/cpu4-after-storm-{1,3}.heapsnapshot, cpu4-budget-failure-trace.json, native-after-storm-{1,3}.heapsnapshot, and native-budget-failure-trace.json. They are not committed.

Found in the production Tab-switching storm for #1338. Related: #1338 and #1233. Three 120-second storms on one Chromium page left detached Mail `<main class="mail-view">` nodes after forced GC. In the VM heap snapshots, detached Mail roots grew from 9 after storm 1 to 28 after storm 3 without CPU throttling, and from 5 to 15 with 4× CPU throttling. The native retaining path is: `(GC roots) → Global handles → NativeContext → Window.fetch → module context → SourceTextModule → Cell → #s.reactions[] → reaction.fn → closure context → detached Mail <main>` The production snapshot keeps the Svelte callback unnamed, so it cannot map the final closure to a source function. The retained DOM identifies `MailView` in `apps/web/src/lib/mail/MailView.svelte`, mounted by `apps/web/src/routes/mail/+page.svelte`. Review the component effects and `onDestroy` teardown (MailView.svelte around line 958) and add a repeated Tab-switch lifetime regression. The same run measured 758/796 requests while Mail was selected, with max in-flight counts 9/8 and 7/25 aborted. The reader prefetch worker in `MailView.svelte` runs four jobs, each requesting a thread and message. `onDestroy` aborts the shared controller, but does not call `clearQueuedReaderPrefetch`; check whether queued jobs and Svelte reactions can retain departed views. Heap snapshots and traces are local ignored artifacts: `artifacts/tabstorm-1338/cpu4-after-storm-{1,3}.heapsnapshot`, `cpu4-budget-failure-trace.json`, `native-after-storm-{1,3}.heapsnapshot`, and `native-budget-failure-trace.json`. They are not committed.
Commenting is not possible because the repository is archived.
No labels
No milestone
No project
No assignees
1 participant
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
kayg/calternal-v0#1375
No description provided.