Repository navigation
Description
What happens
The window's renderer process grows steadily for as long as wmux stays open and
never releases the memory, while every other wmux process stays small.
I first saw this on 2.33.0, updated to 2.42.1 hoping v2.40.0 (#346) had fixed it
as a side effect, and registered the prediction before measuring: under
300 MB after a day would mean fixed, 550-600 MB would mean it survived.
2.42.1 - same renderer process throughout, no restart
| uptime | renderer RSS |
|---|---|
| 0.03 h | 241 MB |
| 0.22 h | 174 MB |
| 2.37 h | 268 MB |
| 22.74 h | 575 MB |
14.7 MB/h. It landed inside the predicted "still leaking" band.
2.33.0 - for comparison
| uptime | renderer RSS |
|---|---|
| 50 h | 1048 MB |
| 115 h | 3258 MB |
| 126 h | 1666 MB (restart in between) |
13-20 MB/h. The rate is unchanged between the two versions.
The part that looks diagnostic: closing 8 of 11 workspaces did not free
anything. RSS went 3258 -> 3382 MB across the closures and kept climbing to
3406 MB. So this is not retained scrollback belonging to live surfaces - the
memory is not reachable from the surfaces that went away.
Expected: RSS roughly proportional to the live surfaces and their scrollback,
and a drop when surfaces are closed.
Steps to reproduce
- Open several workspaces with terminal panes and leave long-running agent
sessions in them (Claude Code here). - Work normally for a day - split panes, zoom, drag tabs between panes.
- Watch the largest wmux process:
Get-Process wmux | Sort-Object WS -Descending | Select-Object -First 1 Id, @{n='MB';e={[int]($_.WS/1MB)}} - Close most of the workspaces and watch the same number.
wmux version
2.42.1 (also reproduced on 2.33.0)
Windows version
Windows 11 Pro, build 22000
Anything else
Possibly related: terminal stutter, and where it is not
Users of this machine see the terminal stutter under load. Measurements that
narrow it down, in case they help:
The main process is healthy. wmux ping has a median latency of 448 ms, but
wmux --help, which never talks to the main process, takes 463 ms. The named
pipe round-trip is therefore effectively zero even with 60 node processes at
60-70 % CPU. The PTY layer and main process are not the bottleneck.
The renderer shows multi-core bursts. Sampling the renderer's
TotalProcessorTime at 50 ms resolution (2-second averages are far too coarse
to see sub-second stalls - a 300 ms full-core stall reads as 0.6 % on 16 cores):
| heap 292 MB | heap 586 MB | |
|---|---|---|
| p99 (% of ONE core) | 261.7 | 420.7 |
| max | 380.9 | 480.5 |
Over 100 % of one core requires several threads at once, which is what parallel
major-GC marking looks like. The peaks grew as the heap grew. Caveat, stated
honestly: the two runs were not under comparable load (41 vs 24 node
processes), so this is suggestive, not conclusive.
A plain terminal on the same machine under the same load does not stutter.
That rules out simple CPU contention.
Ruled out, so you do not have to
- Not system memory pressure: commit 57-58 % of 71.9 GB, 9-11 GB available.
- Not the disk: 97-99 % idle.
- Not the GPU path: GPUCache and DawnWebGPUCache are both populated.
- Not WebGL context exhaustion: only 4 surfaces existed.
- Not transparency:
terminalBgOpacity: 88is gated behindwindowTransparency,
which is off. - Not scrollback size:
scrollbackLines: 5000. - Not Windows Defender: 754 samples over 71 minutes under full load, zero
samples above 3 %, max 0.0 %. - Not renderer process priority: it stayed at Normal through 60 consecutive
samples, including while another app held the foreground.
Why this report has no heap snapshot, and no patch
The DevTools endpoint on 9222 accepts a connection, but the single page target
there is a stub that never answers Runtime.evaluate - not even 1+1. That may
be related to #157. Without it I cannot name the retaining object, and I would
rather file an accurate observation than guess at a fix.
All 11 releases newer than 2.33.0 were checked: none of their notes mention
memory, a leak, RSS or performance, so this was never knowingly fixed.
Activity
fix(renderer): release state that closed surfaces and unread notifica…
amirlehmam commentedon Oct 27, 2026
Thanks for this report, especially the prediction registered before measuring and the observation that closing 8 of 11 workspaces freed nothing. That pointed straight at state kept after a surface goes away.
v2.46.0 (9d351f2) fixes three retention paths found by auditing what the renderer keeps per surface and per workspace:
Stopin a pane nobody focused, and every notification of a closed workspace (which can never be read by focusing it), stayed forever, and each new one copied the whole array. The cap now also evicts the oldest unread entries, and closing a workspace drops its notifications.pty.has()was in flight attached its PTY listeners after cleanup had already run, leaking them and the disposed xterm they hold. That callback now bails out once disposed.To be transparent: this came from a code audit, not from a heap snapshot of your workload, so I can't promise it covers all of your 14 MB/h. I'm closing this as fixed in 2.46.0, but your measurement is the real test. If you can run the same protocol on 2.46.0 (same renderer process, ~24 h, plus a before/after on closing workspaces), please post the numbers here and I'll reopen if it is still climbing. A DevTools heap snapshot early and late in the run would help narrow down anything left.
MarcusJenshaug1 commentedon Oct 28, 2026
Ran the same protocol on 2.47.0 (so the 2.46.0 fix is in). One renderer
process, no restart, 24 h, with the load recorded next to every sample.
Short version: partly better, not fixed, and the way I was measuring it (and
the way my original report measured it) turns out to be unreliable.
Something in the fix works: memory now comes back
It gave back 131 MB when the agents stopped and the surfaces went away. That is
what fix #2 (dropping per-surface state on close rather than on PTY exit)
should look like, and I never saw it on 2.42.1: there the renderer sat at
580 MB at 27.96 h after the load dropped and did not move.
I checked that the drop is real and not Windows trimming the working set:
WorkingSet504 MB vsPrivateMemorySize506 MB at that moment. They match, sonothing had been paged out. Peak working set over the run was 680 MB.
But it does not return to baseline, and it still climbs fast under load
above where it started.
So the growth is driven by agent activity, not by uptime, and a portion of each
burst is retained permanently.
The measurement problem, which affects my original report too
Within a single process, the difference between a loaded sample and an idle one
was 131 MB. That is larger than the difference between the two versions. A
single RSS reading is therefore close to meaningless here unless the load at
that instant is recorded with it.
Comparing like with like:
Under load there is no improvement. The improvement is entirely in the release
behaviour. My original "14.7 MB/h, never released" headline was built on
loaded samples only, and I should not have stated the rate without the load.
The notification array is not where the remaining memory is
Checked directly with
wmux list-notificationsat 22.6 h and 566 MB:A 69-element array copied three times an hour costs nothing, so fix #1 is not
where the residual 251 MB lives. Probably worth not spending more time there.
(I also thought I had found notifications retained for a closed surface. I had
not:
wmux list-surfacesandlist-windowsare scoped to the calling pane, sothe surface I took for dead was alive in another workspace. Retracted.)
Still no heap snapshot, and precisely why
The debug port will not allow one, on 2.47.0 exactly as on 2.42.1:
GET /json/versionanswers: Chrome/150.0.7871.46, V8 15.0.245.13, protocol 1.3GET /json/listreturns one target,type: page,id: 1, with emptytitle,urlanddevtoolsFrontendUrlws://localhost:9222/devtools/page/1connects with no errorRuntime.evaluatewith1+1,HeapProfiler.enableandTarget.getTargetseach timed out after 6 s, withno response and no error frame.
It answers discovery but not the protocol. Possibly the same as #157. While
that holds, nobody can give you a heap snapshot from a real workload, which is
the one piece of evidence that would localise the remaining 251 MB.
Second-hand, offered as hearsay only
Several people I know who use wmux report the same stutter. I have no versions,
no measurements, and cannot interview them, so this is only weak evidence that
it is not specific to my machine. Subjectively this version felt better to me,
but I had a quiet day, and given the load dependence above I would not count
that as evidence either.
Environment
Windows 11 Pro 10.0.22000, 16 logical cores, 32 GB. wmux 2.47.0.
Chrome 150.0.7871.46, V8 15.0.245.13. Workload: Claude Code agent sessions,
12 to 24 node processes, 2 to 3 workspaces. Same renderer process (pid 46328)
for all samples, verified by pid and start time.
Tell me what you would like measured next and I will run it.