Desktop app spawns ~17 git processes per second continuously (Windows), amplifying a kernel pool leak into ~6 GB/day
Summary
On Windows, the desktop app continuously spawns git.exe at a very high rate — measured 15–20 process starts per second, sustained, each with its own conhost.exe. That is ~2 million short-lived processes per day from a single open app.
This is wasteful on its own, but on this machine it also acts as a ~25× amplifier for a separate kernel-level defect (Windows Defender's WdFilter.sys leaks one process-object reference per created process), turning a negligible leak into ~6 GB of non-paged kernel pool per day, after which the machine can no longer shut down cleanly and has to be power-cycled.
Measurements
Process starts captured with WMI Win32_ProcessStartTrace (ordinary process sampling misses them — these processes live under 40 ms):
starts in 10 s: 297
git.exe 191
conhost.exe 97
Parent attribution, same trace:
git spawned by: claude (pid 19804) 97 times in 8 s
The parent is the app's node utility process:
claude.exe --type=utility --utility-sub-type=node.mojom.NodeService
The command being run repeatedly is a plain git invocation against the open project directory.
What does NOT change the rate
Each of these was measured before/after, 10-second windows:
| action | git starts / 10 s |
|---|---|
| baseline | 198 |
| archived every session except the current one | 198 |
| restarted the desktop app completely | 173 |
| closed the diff / changes panel | 152 |
So it is not a runaway loop accumulated over a long session, not per-session, and not tied to the diff panel being open. The app also keeps a change indicator on its icon, which may be what keeps the polling alive regardless of the panel.
Environment
- Windows 10 22H2 (10.0.19045), 47 GB RAM
- Claude Code desktop app 1.52386.6
- One project open (a Go monorepo), git repo on a local NTFS disk
Why it matters beyond CPU
Every created process on this machine leaks its EPROCESS and token in the kernel pool (confirmed with LiveKD + object reference tracing: gflags -ko -t Proc, then !obtrace on a terminated process object — the outstanding reference is taken by WdFilter.sys via PsLookupProcessByProcessId). That is Microsoft's bug, not this app's. But the app's polling rate is what makes it fatal:
- kernel pool with the app open, idle: +300–700 MB per hour
- a full 13-minute CI run of the project: +206 MB (i.e. less than an hour of the app sitting idle)
- non-paged pool reaches the danger zone (3–4 GB) within a working day, and the machine then fails to reboot from the OS
Suggested fix
Poll git on an event (file-system watch / focus change) or at a human interval (seconds, not 60 ms), and reuse a single long-lived git process where possible. Even a 1-second interval would be a 20× reduction.
Showing cached comments. Read the full discussion on GitHub ↗
4 Comments
I have a similar problem, not sure if it's the exact same bug, but here is the report straight from claude's mouth. Seems related to #94655 too.
Title: Desktop app spawns runaway orphaned git diff processes, possibly causing file write issues
The Claude Code desktop app (Windows) repeatedly spawned git.exe processes running the same command against the same commit, piling up to 100+ concurrent orphaned processes:
Repro/observations:
Environment: Windows 11 Enterprise, Claude Code desktop app, Windows PowerShell + Git Bash.
Independent reproduction on a second machine, with a reference trace. Same pattern as this issue; the amplification here comes from the Claude Code engine's per-agent git calls rather than only from the desktop app's idle polling.
Environment
cmd\git.exewrapper ->mingw64\bin\git.exe)Who creates the processes
Command lines captured by polling the process list every 15 ms (60 s windows):
| situation | git.exe starts / min | what |
|---|---|---|
| idle, four sessions open, no agents | 13 | the diff pane:
merge-base,rev-list --left-right --count,ls-files --others,diff ... <commit>|| ~16 subagents working (one workflow) | ~1,000 | per minute ~84x each of
status --porcelain --ignore-submodules=dirty --untracked-files=normal,remote get-url origin,rev-parse --abbrev-ref HEAD,config -z --get-regexp ^(remote\..+\.(url\|pushurl)\|remote\.pushdefault\|branch\..+\.remote)$,symbolic-ref --short refs/remotes/origin/HEAD, plus ~92xstatus --porcelain=v2 -z --untracked-files=normal --ignored=no --no-renames --ignore-submodules=all|| 19 subagents starting | 1,153 in one minute | same bundle |
So the five-command bundle runs roughly 5 times per minute per active agent, parented directly by the engine's
claude.exe. Every call is three processes (wrapper git.exe, real git.exe, conhost.exe).git statusalso walks the whole working tree each time (here >10,000 files).What each process costs
Every exited process stays behind as a process object: after two hours, 123,000 exited process objects against ~175 live processes, none freed between 5-minute censuses. A system-wide handle-table scan (SystemExtendedHandleInformation, matched on object address) found only 2 user-mode handles to them. Nonpaged pool grew ~6-7 KB per exited process (tag
Proc~3.7 KB, plusMiP2,File,ExSa,smStin step, and ~2 kernel Event objects each). Over a 100-agent workflow: nonpaged pool 860 MB -> 1,480 MB in two hours. On 2026-09-27 two such workflows drove it to 5.7 GB and froze the machine.Reference trace (
gflags /ko /t Proc, then!obtracein LiveKD)One fresh
cmd.exeprocess object after exit:HandleCount: 0 PointerCount: 1.The unbalanced
Dfltchain:nt!PsLookupProcessByProcessId<-WdFilter<-nt!PspCallProcessNotifyRoutines. It moves the CID-table reserve onto the object (+32768).nt!PspClearProcessThreadCidRefsreturns 32705.PspInsertThreadduringNtCreateUserProcess) it releases only the deeper one. That is consistent with the WdFilter finding in this issue.Suggested fix on the Claude side (independent of the Defender bug)
mingw64\bin\git.exedirectly, which saves the wrapper process and the conhost..gitwithout spawning a process.Even with the kernel leak fixed, ~1,000 short-lived processes per minute, each walking a large working tree, is a heavy load on its own.
Follow-up to my comment above: a platform-version test on the same machine.
MpCmdRun -ResetPlatformplus a reboot put Defender back on the in-box platform. The service now runs 4.18.2201.11, and the loadedSystem32\drivers\WdFilter.sysandWdNisDrv.sysare also 4.18.2201.11 (from Jan 2022). Before the reset, WdFilter loaded fromdrivers\wd\and was 4.18.26080.4.Test: 200x
cmd /c exit(400 processes including conhost), then\Objects\Processesminus live processes:| Defender platform / loaded WdFilter | exited processes left behind |
|---|---|
| 4.18.26080.4 | +406 |
| 4.18.2201.11 (in-box) | +414 |
So the September Defender platform updates are not what introduced the leak on this machine. Either the reference is held in every WdFilter version, in which case the leak is old and only became expensive with the process rate, or the holder is another in-box component.
On this machine the likelier recent change is the rate of process creation: the per-agent git bundle described above, about 5 bundles per active agent per minute, three processes per git call. That makes reducing the git spawning on the Claude side the practical fix, independent of who holds the reference.
Second follow-up from the same machine: the per-agent git bundle is tied to the working directory being a git repository.
I ran a session with several subagents doing file work (OCR and renaming) in a folder that is not a git repository, and captured process starts for 60 s:
| agents running in ... | git.exe starts / min from the engine (
claude.exewith--output-format stream-json) | from the desktop app's diff pane (other repo sessions open) ||---|---|---|
| a large git repo (earlier comment) | ~1,000 (five-command bundle, ~5x per agent per minute) | ~13-20 |
| a non-git folder | 0 | 16-30 |
So the
status --porcelain/remote get-url/rev-parse/config --get-regexp/symbolic-refbundle comes from agent activity inside a repo only. For anyone hit by the kernel-pool growth, a practical workaround until the polling is reduced is to run agent-heavy work that does not need the repo from outside it.For completeness, the other continuous spawner on this machine was not Claude-related. ASUS
AsusFCNotification.exe(fast charging Notifier) startedcmd.exe -> ITERHPGen.exeabout 37 times per minute, roughly 110 processes per minute with the conhosts. On a system where every exited process leaks ~6-7 KB of nonpaged pool, that alone is ~1 GB per day. Stopping it and removing its Run entry took the idle spawn rate from ~165 to ~55 processes per minute.