anthropics / anthropics/claude-code

[BUG] Backend busy-polls at ~266k syscalls/sec with zero file I/O, holding 1.1 cores per process indefinitely (Windows, 2.1.234)

Đang mở
#89,255 0 bình luận 0 reaction 0 người được giao Xem trên GitHub
area:mcp area:plugins bug perf:cpu platform:windows
Ngôn ngữ chính
Python
Star
145k
Fork
23.1k
Chỉ số merge pull request
Chỉ số pull request đang chờ

Mô tả

## Summary

Claude Code backend processes enter a permanent busy-poll and hold ~1.1 CPU cores each, indefinitely, on Windows. This is measured rather than inferred: the spinning processes perform **zero file I/O** while issuing **~266,000 non-file I/O operations per second each**.

Related but closed without a fix: #11473 (closed "not planned"), #22275 (closed as duplicate), #19393, #30807, #17148. Filing fresh because those are stale, none has Windows syscall-level numbers, and none includes a control group.

## Environment

| | |
|---|---|
| Claude Code | 2.1.234 |
| OS | Windows 11 Home 26100 |
| CPU | AMD Ryzen 7 7800X3D, 8C/16T |
| RAM | 94.9 GB |
| Shape | One app instance (1 window) hosting ~40-56 `claude.exe` backends |

## Measurement

Four spinning backends, sampled over 5 seconds each via `Win32_Process` counters:

```
pid 18500 cpu+ 6.2s fileIO+0 otherIO+1,359,847 threads 35 handles 361
pid 14796 cpu+ 5.7s fileIO+0 otherIO+1,333,536 threads 35 handles 349
pid 10656 cpu+5.62s fileIO+0 otherIO+1,304,113 threads 36 handles 390
pid 22876 cpu+5.45s fileIO+0 otherIO+1,275,591 threads 35 handles 422
```

`ReadOperationCount + WriteOperationCount` delta is **exactly zero**. `OtherOperationCount` delta is ~1.3M in 5s, i.e. **~266,000 syscalls per second per process**. CPU delta of 5.7s over 5s wall = ~114% of a core.

Nothing is being read or written. That is a wait syscall returning immediately instead of blocking, which matches the `recvfrom() -> EAGAIN -> retry` trace in #11473 exactly, on a different OS.

Thread and handle counts are stable across samples, so this is not a leak.

## What it costs

With 13 backends spinning, the whole machine sat at a flat 100%:

```
8 one-second samples: 100, 100, 100, 100, 100, 100, 100, 100
min 100 max 100 avg 100
```

Two unrelated 9-minute build jobs then overran a 10-minute ceiling. `\Processor Information(_Total)\% Processor Utility` read 109.5%, so the CPU was turboing above base: this is not thermal throttling.

Worth noting for anyone triaging: **Task Manager under-reports this badly** (61% against a true 100%), because at saturation it cannot get scheduled often enough to sample itself. Performance-counter readers are accurate; Task Manager is not. That may be why some reports of this get dismissed.

## Ruled out

- **Not orphaned processes.** All four spinners had live parents, all sharing one app instance.
- **Not user hooks or file watchers.** This project runs heavy `SessionStart`/`PreToolUse` hooks; a hook scanning the tree would move `fileIO`, and `fileIO` is flat zero throughout.
- **Not thermal throttling.** See the 109.5% utility figure above.
- **Not a handle or thread leak.** Both counts stable.

## A correlation worth investigating, and a negative result

Every spinning backend had exactly one notable child:

```
cmd.exe /d /s /c "npx -y @modelcontextprotocol/server-pdf --stdio"
```

That is the bundled **pdf-viewer** plugin's MCP server, communicating over a stdio pipe. A stdio pipe poll is consistent with the syscall signature.

Control group, sampled over 5s across all `claude.exe`:

| | count | avg | notes |
|---|---|---|---|
| **With** the `server-pdf` child | 34 | 25% of a core | 8 of them at ~100% |
| **Without** it | 22 | 2% of a core | max 31%, none spinning |

So the pdf MCP child appears **necessary but not sufficient**: nothing without it spins, but only 8 of 34 with it do. During this session the pdf MCP server was observed disconnecting and reconnecting, which may be the trigger.

**However, killing it does not stop an already-spinning process:**

```
BEFORE: pid 18500 at 97% of a core
killed the server-pdf child and its 2 grandchildren
AFTER: pid 18500 at 86% of a core (control pid 22876, child still alive: also 86%)
```

So once started the loop is self-sustaining and survives removal of the suspected trigger. I am deliberately **not** claiming pdf-viewer as the cause. Identifying the actual polled handle needs an ETW trace.

## A second, separate problem

The same bundled plugin had spawned **100 concurrent `server-pdf` processes** holding **6.77 GB** (avg 69 MB each), on a machine where nothing was using PDF tooling:

```
server-pdf processes: 100
RAM held: 6.77 GB
total claude.exe: 56
```

There appears to be no supported way to disable it: it is not in `installed_plugins.json`, not in `enabledPlugins`, and `claude plugin list` does not show it. A bundled plugin that spawns one `npx` process per session with no opt-out is worth a look independently of the CPU bug.

## What would close this out

An ETW/WPR trace on a spinning process would name the exact call. I did not have Windows Performance Recorder available. If a maintainer can say which handle the event loop is expected to block on, that is probably enough to spot the regression by inspection.

## Reproduction

Not reliably reproducible on demand. It appears on a long-lived box running many concurrent sessions under one app instance, and once a backend starts spinning it never recovers: only ending that session frees the core.

Hướng dẫn đóng góp

Chưa lập chỉ mục được hướng dẫn đóng góp cho kho mã nguồn này

Hướng nghiên cứu

Start with an ETW/WPR trace of a spinning Windows backend to identify the exact call and handle being polled. Compare the trace with the server-pdf stdio connection and the observed disconnect/reconnect behavior. Done means identifying the regression and stopping the persistent busy-poll without relying on killing the session.

Do mô hình lập chỉ mục viết ra từ nội dung của issue.

Đánh giá

Công nghệ
node.js, python
Lĩnh vực
backend, operating-systems
Loại issue
Lỗi
Độ khó
5/5
Thời gian dự kiến
Hơn một tuần
Mức độ hoạt động
Sôi nổi
Độ rõ ràng
Cần làm rõ
Mức phù hợp với người mới
25/100

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.