Summary
The Dormouse webview renderer leaks roughly 25 MB/hour on a completely idle terminal. Growth tracks wall-clock time, not terminal output. Measured over a 9.6-hour idle window the webview grew 73 MB → 322 MB (4.4x) while only 2.5 MB of PTY output flowed through the whole session.
The pty-host process is unaffected and behaves well (see "What is not leaking" below).
Evidence
Sampled PSS every 30s from /proc/<pid>/smaps_rollup, with terminal output volume taken from the pty-host's /proc/<pid>/io rchar counter as an activity proxy.
Overnight run, machine idle:
23:30 67 MB 04:00 187 MB
00:30 94 06:00 240
01:30 120 07:30 279
02:30 146 08:30 306
03:30 173 09:03 322 <- peak
These are 30-minute minima, not means. The floor rose monotonically across all nineteen buckets with no reversal — memory is never reclaimed. A sawtooth (cache/scrollback churn) would show a flat floor with oscillating peaks.
Reproduced across three separate renderer processes, including two spanning an active workday of builds and one spanning a dead-quiet night:
| instance |
duration |
range |
rate |
| A |
1.0 h (active) |
77.6 → 108.2 MB |
+19.7 MB/h |
| B |
7.3 h (active) |
70.1 → 273.0 MB |
+27.0 MB/h |
| C |
9.6 h (idle) |
70.4 → 322.3 MB |
+25.1 MB/h |
Near-identical slope under a full workday of terminal activity and under an idle night is the key result: output volume is not the driver.
Control: the VS Code main window renderer, same Electron, same night, same host: +6.55 MB/h — ~4x slower. So this is not baseline Electron drift.
Each instance starts around 70 MB, so the leak appears to begin at webview creation.
What is not leaking
The pty-host process is a clean bill of health, worth recording so it can be ruled out:
- +0.49 MB/hour over a 7.3-hour continuous lifetime, and it reclaims — hourly means rose 27.8 → 34.9 MB then fell back to 32.4 MB and held. Bounded sawtooth.
- Process lifecycle is clean: exactly one
pty-host at a time, no orphans across several extension-host restarts, and child count tracked open panes with no churn or accumulation.
Impact
At 25 MB/h the webview passes ~600 MB in a day and ~1 GB in under two, with nobody typing.
This compounds a second issue on memory-constrained machines: processes spawned from a Dormouse terminal inherit VS Code's cgroup (app-code-*.scope), so on a systemd-oomd system the leak is charged to the editor's scope and counts toward the kill decision. On a 6.6 GB laptop this contributed to systemd-oomd killing the whole VS Code scope. An editor left open over a weekend could reach the threshold from the leak alone.
Suspects
Idle growth on a clock points away from scrollback and toward something on a timer. Ranked by fit, unverified:
lib/src/lib/quiesce-detector.ts / lib/src/lib/alert-manager.ts — the Activity layer is timer-driven by design (docs/specs/alert.md); an interval appending without eviction matches this signature.
lib/src/lib/terminal-state-store.ts — command runs / title candidates, if they accrue per tick rather than per command.
lib/src/lib/session-dirty.ts — its own comment notes state changes "even with no user activity", which is exactly the observed condition.
Reproduction
- Open a Dormouse panel in VS Code with one idle terminal. Do not type.
- Sample the webview renderer's PSS every 30s:
awk '/^Pss:/{s+=$2} END{print s}' /proc/<renderer-pid>/smaps_rollup
The webview is the VS Code renderer starting at ~70 MB (the main window renderer starts at ~200 MB+).
- Growth of ~25 MB/hour appears within an hour and stays linear.
Fastest path to a culprit: Developer: Open Webview Developer Tools, take heap snapshots an hour apart and compare retained sizes. At this rate the delta should name the retaining object directly.
Environment
- Dormouse extension
1.1.0
- VS Code
1.135.0 (Electron 42.8.1), Wayland
- Ubuntu 26.04.1 LTS, kernel 7.0.0-30-generic, x64
- 6.6 GB RAM, systemd-oomd active
Summary
The Dormouse webview renderer leaks roughly 25 MB/hour on a completely idle terminal. Growth tracks wall-clock time, not terminal output. Measured over a 9.6-hour idle window the webview grew 73 MB → 322 MB (4.4x) while only 2.5 MB of PTY output flowed through the whole session.
The
pty-hostprocess is unaffected and behaves well (see "What is not leaking" below).Evidence
Sampled PSS every 30s from
/proc/<pid>/smaps_rollup, with terminal output volume taken from the pty-host's/proc/<pid>/iorcharcounter as an activity proxy.Overnight run, machine idle:
These are 30-minute minima, not means. The floor rose monotonically across all nineteen buckets with no reversal — memory is never reclaimed. A sawtooth (cache/scrollback churn) would show a flat floor with oscillating peaks.
Reproduced across three separate renderer processes, including two spanning an active workday of builds and one spanning a dead-quiet night:
Near-identical slope under a full workday of terminal activity and under an idle night is the key result: output volume is not the driver.
Control: the VS Code main window renderer, same Electron, same night, same host: +6.55 MB/h — ~4x slower. So this is not baseline Electron drift.
Each instance starts around 70 MB, so the leak appears to begin at webview creation.
What is not leaking
The
pty-hostprocess is a clean bill of health, worth recording so it can be ruled out:pty-hostat a time, no orphans across several extension-host restarts, and child count tracked open panes with no churn or accumulation.Impact
At 25 MB/h the webview passes ~600 MB in a day and ~1 GB in under two, with nobody typing.
This compounds a second issue on memory-constrained machines: processes spawned from a Dormouse terminal inherit VS Code's cgroup (
app-code-*.scope), so on a systemd-oomd system the leak is charged to the editor's scope and counts toward the kill decision. On a 6.6 GB laptop this contributed tosystemd-oomdkilling the whole VS Code scope. An editor left open over a weekend could reach the threshold from the leak alone.Suspects
Idle growth on a clock points away from scrollback and toward something on a timer. Ranked by fit, unverified:
lib/src/lib/quiesce-detector.ts/lib/src/lib/alert-manager.ts— the Activity layer is timer-driven by design (docs/specs/alert.md); an interval appending without eviction matches this signature.lib/src/lib/terminal-state-store.ts— command runs / title candidates, if they accrue per tick rather than per command.lib/src/lib/session-dirty.ts— its own comment notes state changes "even with no user activity", which is exactly the observed condition.Reproduction
awk '/^Pss:/{s+=$2} END{print s}' /proc/<renderer-pid>/smaps_rollupThe webview is the VS Code renderer starting at ~70 MB (the main window renderer starts at ~200 MB+).
Fastest path to a culprit:
Developer: Open Webview Developer Tools, take heap snapshots an hour apart and compare retained sizes. At this rate the delta should name the retaining object directly.Environment
1.1.01.135.0(Electron 42.8.1), Wayland