anthropics / anthropics/claude-code

[BUG] Windows: memory-pressure governor evicts `0 of 0` idle sessions while 15+ are live - app reaches 12.4 GB RSS, stalls, must be force-killed

Offen
#92,059 1 Kommentar 0 Reaktionen 0 zugewiesene Personen Auf GitHub ansehen
area:desktop bug has repro perf:memory platform:windows
Vorherrschende Sprache
Python
Sterne
145k
Forks
23.1k
PR-Merge-Kennzahlen
PR-Kennzahlen ausstehend

Beschreibung

### Preflight Checklist

- [x] I have searched existing issues and this hasn't been reported yet
- [x] This is a single bug report
- [x] I am using the latest version

### What's Wrong?

**Environment**

- Windows 11 Home Single Language, 10.0.26200.9168
- Intel i5-12450HX, **16 GB RAM**
- Claude desktop **1.46388.2.0** (MSIX, `Claude_pzs8sxrjxfjjc`), claude-code backends 2.1.258 / 2.1.260
- Remote Control connected; typically 10–19 sessions open

**Summary**

The desktop app has a memory-pressure governor (`CliGovernor`) that evicts idle sessions when RAM runs low. Across 4 days of logs it fired **44 times and found no eviction candidates on 43 of them** — including at `critical` level with **32 MB of system RAM free** — while simultaneously reporting 9–19 live sessions. The process tree then stalls, the UI stops responding, and the app has to be force-killed, which lands the user in the relaunch failure of #92005.

The eviction machinery itself works. The candidate selection is what fails.

**Evidence** — `%LOCALAPPDATA%\Claude\logs\main.log`, span 2026-08-31 08:49 → 2026-09-04 08:08, 5,316 `[process-memory]` samples.

Governor outcomes over that window:

```
44 [CliGovernor] memory pressure events (35 warning, 9 critical)
43 "evicted 0 of 0 idle session(s)" <-- empty candidate pool
1 "evicted 1 of 11 idle session(s)" <-- works when it finds candidates
```

Effective session counts reported at those moments: 9, 11, 13, 14, 15, 17, 18, 19 — never zero.

The critical event, verbatim:

```
2026-09-03 22:36:33 [warn] [CliGovernor] memory pressure (critical): evicted 0 of 0 idle session(s), 15 effective
```

System free RAM in the adjacent `[process-memory]` sample: **32 MB of 16,108 MB**.

### Leading hypothesis: the idle reaper's veto empties the governor's candidate pool

Five seconds before that critical event, the warm-lifecycle reaper tried to pause every idle session and was vetoed on each one:

```
22:36:28 [info] [WarmLifecycle:session] Idle timeout reached, disconnecting local_
22:36:28 [info] [CCD] Skipping pause for session local_ - remote control is active (startup-policy bridge)
```

...repeated for every session in turn. Frequency of each veto reason across the log:

```
587 remote control is active (startup-policy bridge)
10 1 active background task(s)
9 2 active background task(s)
```

`active background task(s)` is a legitimate veto and is rare. `remote control is active (startup-policy bridge)` appears to be applied per-session and unconditionally whenever Remote Control is connected — 587 times between 2026-09-03 00:47:10 and 2026-09-04 01:23:43 — which would explain a permanently empty idle pool.

To be precise about what the logs do and don't establish: they establish the empty pool, the veto, and the correlation; they do not establish the causal link inside the code. But the one occasion the governor *did* see candidates, it behaved correctly and immediately:

```
23:07:54 [warn] [CliGovernor] memory pressure (warning): evicted 1 of 11 idle session(s), 15 effective
23:07:54 [info] [CliGovernor] pressure evicting local_ (idle 481s)
23:07:54 [info] [CCD] Pausing session local_ (governor_evict)
```

So the eviction path is fine. Something is removing sessions from the pool before the governor ever ranks them.

### Consequences observed

- Peak process-tree RSS **12,415 MB** on a 16 GB machine (2026-09-01 10:25:43; 185 children; 762 MB free).
- 97 of 5,316 samples under 1 GB free; 37 under 500 MB; low-water mark **8 MB free** (2026-08-31 19:16:00).
- Peak child process count **239** (2026-09-03 21:36:29).
- Main-process event loop stalls as memory runs out — 3,222 ms, then 8,088 ms blocks — which is the UI hang users report:
```
22:36:00 [warn] [event-loop-stall] main process blocked for 3222ms (... cumulative 21980ms ...)
22:36:54 [warn] [event-loop-stall] main process blocked for 8088ms (... cumulative 30609ms ...)
```
- Windows' own resource-exhaustion detector has flagged `claude.exe` twice, on two different versions: `RADAR_PRE_LEAK_64` for 1.24012.9.0 (2026-08-04) and for 1.44121.4.0 (2026-09-03 21:06, ~90 minutes before the critical event above). In fairness this signal is weak on its own — RADAR also fired for Chrome, MATLAB, `dwm.exe` and OneDrive on this machine over the same period — so I offer it only as corroboration, with the recurrence across two versions being the part worth a look.
- **These episodes are invisible to crash telemetry.** No `Application Error` or `AppHang` WER event is ever recorded for `claude.exe`, because the user force-kills it before Windows declares it hung, and `%APPDATA%\Claude\Crashpad\reports\` is empty. That may be why this is under-reported relative to how often users hit it.

### What Should Happen?

Under memory pressure — certainly at `critical` — the governor should be able to evict idle sessions. A `critical` event that evicts `0 of 0` while 15 sessions are live and 32 MB of RAM remains is the governor failing at precisely the moment it exists for.

Suggested directions:

1. **Make the veto pressure-level-aware.** Keeping a session warm for Remote Control responsiveness is reasonable at `none`/`warning`; at `critical`, staying alive matters more than staying warm.
2. **Distinguish "pinned" from "not idle".** A session idle for 481 s is an eviction candidate regardless of *why* it is pinned. Today such sessions appear to be excluded from the pool outright rather than ranked lower.
3. **Log the rejection reasons at pressure time.** `evicted 0 of 0` cannot distinguish an empty pool from a fully-filtered one. Emitting the filter counts would have turned this investigation into a one-line diagnosis.
4. **Consider a ceiling on child process count and tree RSS relative to physical RAM.** 239 children and 12.4 GB on a 16 GB machine leaves nothing for the OS.

### Steps to Reproduce

1. 16 GB Windows 11 machine, Claude desktop, **Remote Control connected**.
2. Open ~15 sessions and work across them for several hours.
3. Watch `%LOCALAPPDATA%\Claude\logs\main.log` for `[CliGovernor] memory pressure`.
4. Observe `evicted 0 of 0 idle session(s), N effective` with N well above 0, preceded by `[CCD] Skipping pause ... remote control is active (startup-policy bridge)` for every session.
5. Continue until `[event-loop-stall]` reaches multiple seconds. The app becomes unresponsive and must be force-killed — after which relaunch fails per #92005.

### Claude Code Version

Desktop 1.46388.2.0; claude-code 2.1.260

### Platform

Windows

### Additional Information

The failed relaunch after the force-kill is #92005, where I have added the Restart Manager / exclusive-lock mechanism. This issue is about what causes the hang; that one is about what blocks the restart.

Beitragsleitfaden

Für dieses Repository ist kein Beitragsleitfaden indexiert

Rechercherichtung

Start with the `[CliGovernor]`, `WarmLifecycle:session`, and `[CCD]` log paths in `%LOCALAPPDATA%\Claude\logs\main.log`, comparing the empty candidate-pool events with the one successful eviction. Reproduce with Remote Control connected and several sessions, then trace how the veto affects candidate selection; done means idle sessions can be evicted under critical pressure and the rejection counts make empty-pool causes distinguishable.

Vom Indexierungsmodell aus dem Issue-Text verfasst.

Bewertung

Bereich
desktop-dev, operating-systems
Issue-Typ
Bug
Schwierigkeit
4/5
Geschätzter Aufwand
3-5 Tage
Aktivitätsstatus
Aktiv
Klarheit
Größtenteils klar
Anfängerfreundlichkeit
42/100

Neue Issues direkt in Ihr Postfach

Eine kurze Übersicht über anfängerfreundliche GitHub-Issues.