[Windows 10] DWM Composition handles accumulate after Codex tasks with tool calls

Open 💬 13 comments Opened Jul 14, 2026 by J-ShuJie

Summary

On Windows 10 22H2, I can reproduce persistent growth in DWM's Composition handle count after Codex tasks that make terminal tool calls. A no-tool task that replied only OK did not show the same growth. In one controlled five-call run, the Composition count increased by 22 and remained elevated throughout the 30-second period after the task finished.

After about four days of normal Codex use, DWM had 22,770 Composition handles, compared with 817 after a DWM restart. At that point, dragging an ordinary window could lag by 10 to 20 seconds. Restarting only DWM cleared the accumulated state and immediately restored smooth window movement.

In a separate control, every ChatGPT.exe and codex.exe process was absent for about 5 minutes 35 seconds. No comparable new growth was observed while Codex was closed, but the handles already held by DWM did not fall. So far, they have only been cleared by restarting DWM or Windows.

I cannot yet tell whether the lifetime problem begins in the Codex UI, Electron, Chromium, DirectComposition, DWM, or the graphics driver. This report documents the repeatable trigger and the resource signature.

Environment

  • Windows 10 22H2, build 19045.7417, x64
  • Codex MSIX OpenAI.Codex_26.707.9981.0_x64
  • Internal app version 26.707.72221, build 5307
  • Electron 42.1.0
  • Chromium/ProductVersion 150.0.7871.115
  • One internal display at 2400 x 1600, 60 Hz; no external display
  • Intel Iris Xe Graphics and NVIDIA GeForce RTX 3050 Ti Laptop GPU
  • HAGS enabled (HwSchMode=2)
  • Variable refresh optimization enabled (VRROptimizeEnable=1)
  • MPO disabled (OverlayTestMode=5)

I have seen the same general problem across several Codex desktop updates. The version above is the one used for the controlled captures below.

Reproduction

  1. Start from a low DWM handle count after signing in to Windows or restarting DWM.
  2. Open Codex and create a new task.
  3. Ask it to make several separate, read-only terminal calls, for example:

``powershell
Get-Date
Get-Location
Get-Process -Id $PID | Select-Object Id, ProcessName, HandleCount
git status --short
Get-ChildItem -Name | Select-Object -First 3
``

  1. Record the count and type of DWM handles before the task, while it runs, and for at least 30 seconds after it finishes.
  2. Repeat the task a few times. It is not necessary to keep Codex in the foreground.
  3. For comparison, create a new task that only replies OK and does not call any tools.

Expected: After a task finishes and its status UI settles, DWM Composition handles should return close to their previous baseline.

Actual: Tasks with several tool calls leave a small persistent net increase. Repeating these task cycles gradually builds a much larger DWM-side handle stock.

Controlled results

| Test | Workload | Persistent DWM handle change | Composition change |
| --- | --- | ---: | ---: |
| Plain text control | New task replied only OK; no tools | +5 | -1 |
| Five terminal calls | Five separate read-only calls | +10 | +22 |
| Idle long task view | Visible and idle for about 10 minutes | +2 | Not sampled by type |
| Idle short task view | Visible and idle for about 10 minutes | 0 | Not sampled by type |
| Active task | Running for about 6 minutes | +66 | Not sampled by type |
| Active task, Codex minimized | Running in the background | +55 | Not sampled by type |
| Scheduled task | Natural unattended run | +88 | Not sampled by type |

The two controlled runs used 30-second medians before and after the task. The DWM PID remained unchanged.

DirectComposition trace

I captured the five-call test with the Microsoft-Windows-DirectComposition and Dwm-Core ETW providers.

During the server-reported task interval, DirectComposition recorded four identical 12-resource creation batches for DWM channel 61. None of those 48 resources had a matching release before the trace ended. An identical fifth batch appeared about 2.1 seconds before the server startedAt timestamp, which may reflect local task initialization, but I cannot prove that from this trace.

Every batch had this resource type sequence:

201, 195, 195, 32, 32, 79, 87, 39, 58, 39, 58, 30

The resource handles were sequential and had openShared=false.

This capture did not include the Dwm-Core channel-attribution keywords, so I cannot map channel 61 to a specific client PID. The same batch signature also appeared occasionally outside the task interval. I therefore treat this as a correlation clue rather than proof that channel 61 belongs to Codex.

The capture used Dwm-Core keyword mask 0x21. A follow-up trace should use 0x900021 so that it also records PROCESS_ATTRIBUTION, CHANNEL_OPENED_FOR_PROCESS, CHANNEL_CLOSED_FOR_PROCESS, and COMMAND_PROCESSED_ONBEHALF. The DirectComposition mask can remain 0x5F.

DWM kept the same PID throughout the run. There was no lock-screen transition. Video.UI emitted no DirectComposition create or release events during the task interval, and the ShellExperienceHost burst began only after completion, consistent with the completion notification.

Related report

The closest existing report I found is #16374, which describes progressive Windows shell freezes associated with Codex. This may be part of the same broader problem. The additional evidence here is the DWM handle type, the no-tool control, and the DirectComposition capture.

Package note

The affected package is an Electron 42 and Chromium 150 application, not WebView2. I found task-status and sidebar lifecycle code in the packaged ASAR, but the production package has no source maps, so I could not map the observed resource lifetime to a specific source module.

Evidence retained locally

The most relevant sanitized results are included above. I have also kept the complete ETL, the two run summaries, before-and-after handle type diffs, and the extracted DirectComposition batches. I have not attached the raw ETL because it contains a wider process timeline.

View original on GitHub ↗

13 Comments

codengine · 1 month ago

This issue also affects the CLI version of Codex, and it has been like this at least since 0.13*

codengine · 1 month ago

I let Codex analyze the issue and it figured out that it may relate to this commit:
https://github.com/openai/codex/commit/6b3d82daca540318d074c1ad2afcaba5b3337a3d

... which creates a private desktop per tool call and ignores the return value when it is closed. I am testing a custom build where a shared/reused private desktop is used and will report back

codengine · 1 month ago

Codex created this patch. I deployed the executables and ran thousands of tool calls. The memory and CPU consumption of dwm.exe did not move.

The main cause seems to be that every tool call creates a dedicated private desktop and it's closure is neither checked nor retried.
The attached patch, based on 0.144.5, creates one private desktop per Codex process.

codex-0.144.5-shared-private-desktop.patch

codengine · 1 month ago

10 hours later with 4 agents running in parallel - dwm still only reports 46 MB, load sub 0.1%, all windows are snappy... the main issue is really the desktop creation per tool call and the missing cleanup, or there is a leak in dwm.exe itself.

ManorianOTP · 29 days ago

Adding another Windows reproduction on a current desktop build.

Environment

  • Codex/ChatGPT Desktop package: 26.721.4979.0
  • Windows x64 build: 26200.8875 (25H2)
  • Installed RAM: 32 GiB

Symptom

This is system-wide compositor/input lag, not only a slow Codex window:

  • Composer typing has some latency from launch.
  • After prolonged long-running Codex work, unrelated Windows applications and desktop window movement become severely delayed.
  • After releasing a dragged ordinary window, it can continue moving visually for approximately 10 seconds or more.
  • The slowdown worsens over hours while Codex remains open.

Resource headroom

A live read-only snapshot during the affected session showed approximately:

  • 13.4 GiB physical RAM still available
  • 23% overall CPU load
  • no large population of runaway taskkill.exe or conhost.exe processes

This therefore did not coincide with conventional CPU or physical-memory exhaustion.

The symptom is materially similar to the delayed ordinary-window dragging reported in this issue. It may also overlap with long-thread renderer/event-state growth discussed in #21134, but the important distinction here is that the rest of Windows becomes nearly unusable too.

Expected behavior

Long-running local Codex workflows should not degrade Windows DWM/compositor or system-wide input responsiveness when the machine retains substantial CPU and RAM headroom. DirectComposition/DWM and renderer resources should remain bounded and be released during prolonged background work.

Private prompts, project names, session identifiers, filesystem paths, and raw logs are intentionally omitted. Privacy-safe diagnostics can be collected through the official feedback channel if maintainers specify what additional counters or trace profile would be useful.

josh-robey · 20 days ago

Confirming this is still unfixed in the current Store build, with a concrete Windows 10 reproduction.

Environment

  • OS: Windows 10, x64 (22H2 family)
  • Codex/ChatGPT Store package: OpenAI.Codex_26.803.5235.0_x64__2p2nqsd0c76g0 (current as of Aug 6)
  • The bundled app\resources\codex.exe still imports CreateDesktopW / CloseDesktop, and the sandbox helper (codex-command-runner.exe) still accepts --windows-sandbox-private-desktop and is re-copied into %USERPROFILE%\.codex\.sandbox-bin\ on every launch.

Observed behavior

  • After a few days of normal Codex use (tool-call-heavy sessions), DWM's Composition handle count climbs into the tens of thousands.
  • System-wide input lag follows: window dragging takes 10-20 seconds to respond, unrelated apps stall, and mouse movement degrades.
  • All other metrics are clean while this happens: CPU ~30%, disk queue 0, available RAM in the multi-GB range, GPU well under 20%.
  • Restarting dwm.exe clears the handles and immediately restores responsiveness. Nothing else does - not a GPU driver reset, not killing the renderer tree.

Timeline impact
This has been slowing my PC down for literally 6-7 months. I have been trying to figure out what has been happening the whole time, and it has been progressively getting worse. This needs to be fixed ASAP please - it is killing my PC.

What would help

  • The per-tool-call private desktop creation path (introduced in commit 6b3d82d, March 2026) still has no verified cleanup: CreateDesktopW per command, close result ignored, no retry. The shared-private-desktop patch in this thread (one desktop per process) is a validated direction - thousands of tool calls with zero DWM growth, 10h/4-agent run with DWM at 46 MB.
  • Please either ship the per-process desktop reuse, or add a cleanup that checks/retries CloseDesktop, or expose a supported toggle that stops per-call desktop creation without losing the sandbox isolation. Note that the existing windows.sandbox_private_desktop = false escape hatch does not preserve the isolation - it disables it entirely.

Happy to provide a WPR/ETW trace or Process Monitor capture on request. This has been open since July 14 and is still affecting current builds - it's the difference between Codex being usable and not on Windows 10.

deathy · 17 days ago

Adding DWM-side object counts that quantify this per tool call, plus where the CPU actually goes.

Environment

  • Windows 11 Pro, build 26200 (25H2), x64, 24 logical cores, 64 GiB RAM
  • Codex/ChatGPT Store package OpenAI.Codex_26.803.5235.0_x64__2p2nqsd0c76g0
  • NVIDIA RTX 4070, driver 32.0.16.1088
  • Displays: 3840x2160 @ 60 Hz @ 150% DPI (primary) + 2x 1920x1080 @ 60 Hz @ 100%

Method

Rather than counting kernel handles, I dumped dwm.exe (full memory, MiniDumpWriteDump)
and counted live composition objects by scanning for their vtable addresses:

x dwmcore!CVisual::`vftable'
s -q 0x10000 L?0x7ffffffeffff <vtable address>

Tool-call counts come from ~/.codex/.sandbox/sandbox.<date>.log, counting
setup refresh: spawning ...codex-windows-sandbox-setup.exe occurrences inside each
measurement window.

Both measurements below were taken against the same dwm.exe instance (PID unchanged),
with Codex fully exited before the closing measurement in each case. No other
application was started, closed, or resized during either window.

Results: the leak is a constant per tool call

| | Run 1 | Run 2 |
| --- | ---: | ---: |
| Wall-clock window | 34 min | 177 min |
| Sandboxed command executions | 395 | 359 |
| CVisual delta | +2,393 | +2,182 |
| CDesktopTreeData delta | +2,395 | +2,183 |
| CVisualOcclusionInfo delta | +501 | +391 |
| CVisual per tool call | 6.06 | 6.08 |
| CDesktopTreeData per tool call | 6.06 | 6.08 |

The per-tool-call figure reproduces to within 0.3% across two runs whose durations
differ by 5x. The leak tracks tool-call count, not session length or wall-clock time.
CVisual and CDesktopTreeData stay locked at 1:1 throughout.

None of it is released when Codex exits. Both closing measurements were taken with no
ChatGPT.exe / codex.exe process running; the counts above are what remained.

For scale, immediately after a dwm.exe restart this machine sits at 4,752 CVisual.
Two Codex sessions took it to 9,487 - roughly doubling the entire desktop's composition
tree from ~750 tool calls.

Where the CPU goes

Sampled profile of dwm.exe (xperf -on PROC_THREAD+LOADER+PROFILE -stackwalk profile,
symbols from the public server) once the tree had grown large, showing why this presents
as system-wide lag rather than a Codex-only problem:

CComposition::ProcessComposition                            88.05%
├─ CComposition::PreRender                                  63.41%
│   └─ CComposition::CleanTrees                             60.37%
│       ├─ CPreWalkVisual::CalcTransform                    29.57%
│       └─ CPreComputeContext::PreCompute                   12.97%
└─ CRenderTargetManager::RenderAndPresent                   24.00%
    ├─ ComputeOverlayConfiguration (occlusion)              15.93%
    └─ CDDisplayRenderTarget::RenderAndPresent               7.97%
        ├─ ...DrawVisualTree                                 5.80%
        └─ Present                                           1.66%

DWM walks the visual tree three times per frame plus a transform pre-walk, all O(visual
count). Under 8% of its time is spent actually drawing or presenting - the rest is
bookkeeping over the accumulated tree. On this machine that reached ~90% of one CPU core
with the compositor otherwise idle, and restarting dwm.exe returned it to ~7%.

Happy to re-run with additional counters if that would be useful.

TobyIsADog · 15 days ago

Confirming that this is still happening on a newer Windows Store build.

Environment

  • Codex 26.803.10989.0 (app-server 0.147.0-alpha.6.6)
  • Windows 11 Pro x64, build 26200
  • Intel Arc Graphics 32.0.101.6881 and NVIDIA RTX 4060 Laptop GPU
  • One 2560×1440 display, 32 GiB RAM

What happens

After Codex has been running tool-heavy tasks for many hours, the mouse pointer starts moving in visible steps across the desktop and other applications. The rest of Windows remains responsive. Signing out of Windows or rebooting restores smooth pointer movement, but the problem returns after another long Codex session.

During one affected session, Codex and Windows had been running for about 28 hours. The sandbox log contained 9,688 launches of codex-windows-sandbox-setup.exe. At that point:

  • dwm.exe was using 749–766 MiB of private memory and had about 994 MiB of GPU memory committed.
  • The machine still had 16.1 GiB of available RAM and CPU usage was about 7%.
  • DPC and interrupt activity were low.
  • Windows had recorded no display-driver reset or Codex/GPU-process crash.

This does not look like ordinary CPU or memory pressure, and it matches the DWM accumulation described in this issue.

Why the private-desktop cleanup still looks relevant

The current code still creates a fresh randomized CodexSandboxDesktop-* for a sandboxed process:

Together with the repeatable per-tool-call CVisual and CDesktopTreeData growth reported above, this points to the same failure mode: private desktops are created repeatedly, some composition state is not released, and DWM gradually has more work to do each frame.

A fix should keep the number of private desktops bounded or verify that desktop cleanup actually succeeds and that the related DWM objects return to baseline.

roymasad · 14 days ago

Same issue with win UI lag happening with me also with Codex left running for half a day.

A force kill of dwm.exe is needed to restart it and get the UI back to a normal state.

smallwangcf · 14 days ago

Title: Windows-wide mouse/input stutter persists after opening a second Codex window until all ChatGPT.exe processes are terminated

I am seeing intermittent system-wide mouse/input stutter on Windows while using Codex in the ChatGPT Desktop app. Chrome, File Explorer, and Codex are all affected. An unusual observation is that putting Task Manager in the foreground makes mouse movement feel smooth across the desktop, even when the Task Manager window is small.

The clearest reproduction I have observed is:

  1. End all ChatGPT.exe processes in Task Manager. The system immediately becomes smooth.
  2. Open one Codex/ChatGPT Desktop window and run one Codex task. The system remains smooth.
  3. Open a second Codex/ChatGPT Desktop window. A second task is not required. Mouse stutter starts immediately.
  4. Close both visible ChatGPT/Codex windows. The stutter continues.
  5. End the whole remaining ChatGPT/Codex process group in Task Manager. The system immediately becomes smooth again.

This does not appear to be reliably caused by running two tasks or by web preview itself. Opening the second window appears to trigger or expose a background app-process state that remains after the UI windows are closed.

Read-only snapshots during the lag did not show general resource saturation: CPU was about 15% average (20% peak), DPC about 0.11% average, and interrupts about 0.63% average. The ChatGPT group had about 13 processes and about 3.19 GB private memory. A ChatGPT GPU process used about 10% average / 24% peak 3D, while dwm.exe used about 2.7% average / 3.9% peak. I saw no display-driver reset, DWM, or WHEA error around the second-window reproduction time.

Hardware: 32 GB RAM, NVIDIA RTX 4060 + Intel UHD 770, 60 Hz display. Windows reports build 26200.8875. I also saw one earlier WER RADAR_PRE_LEAK_64 event for ChatGPT.exe, but I cannot prove that it is related.

Could you please investigate whether the Windows desktop app can leave an Electron/Chromium renderer, GPU-process, DirectComposition, or DWM-composition state active after opening a second window or running Codex tools? This is a hypothesis based on the observed behavior, not a confirmed root cause.

I can provide a sanitized diagnostic summary. I have not captured an ETW trace yet because Windows Performance Recorder requires an elevated administrator session.

SayrWolfridge · 13 days ago

Additional sanitized evidence for #33192

No raw ETL, CSV export, screenshot, process tree, command line, or machine-specific path is attached. All times below are relative to the retained trace interval.

Reproduction on a newer build

  • Codex package: 26.810.4967.0
  • Command runner: codex-command-runner-0.148.0-alpha.9.exe
  • Controlled test: eight minimal terminal invocations followed by one sampling invocation
  • Persistent DWM Composition change: +18, exactly +2 per runner invocation

This reproduces the issue on a newer package than the one in the original report.

ETW handle-lifetime evidence

A separate retained ETW slice from package 26.803.10989.0 and command runner 0.147.0-alpha.6.6 contained:

  • 18 DWM Composition creation bursts
  • 111 newly observed Composition objects
  • 81 objects closed within the retained slice
  • 30 objects still outstanding at the end of the slice
  • 14 of 18 creation bursts matched command-runner WindowUpdate events within 50 ms
  • All 126 command-runner WindowUpdate events fell inside those matched burst windows
  • Those 14 runner-associated bursts accounted for 28 of the 30 newly outstanding objects
  • Each matched runner burst created seven Composition objects, closed five, and left two outstanding

The observed enrichment of runner WindowUpdate events around DWM creation bursts was approximately 80x over a uniform-background expectation at a 50 ms window.

Symbolized creation path

The repeated DWM-side creation path was:

dwmredir.dll!CPortBase::PortThread
dwmredir.dll!CSessionPort::ProcessCommand
uDWM.dll!CWindowList::ProcessAsyncDwmMessage
uDWM.dll!CWindowList::DesktopCreate
uDWM.dll!CWindowList::GetGlobalLightSetForDesktop
uDWM.dll!CGlobalLightSet::Create
uDWM.dll!CGlobalLightSet::Initialize
uDWM.dll!CreateCoordinateSpaceVisual / AddNewSharedDistantLightWithType
uDWM.dll!UdwmDcompVisual::CreateSharedVisual
dcomp.dll!Windows::UI::Composition::InteropCompositor::Api::OpenSharedResourceHandle
dcomp.dll!CompositionObject::CreateHandle

Interpretation

The evidence points to per-command Windows sandbox runner lifecycle as the trigger. Each short-lived runner produces a Win32k window update that is followed within milliseconds by DWM desktop/global-light-set creation, with two Composition objects remaining outstanding after the runner exits.

The trace does not establish whether the missing release belongs in the runner, console/window lifecycle, DirectComposition interop, or DWM itself. It does narrow the trigger from the general Codex UI to the per-command Windows runner path.

GaleVale · 4 days ago

Adding sanitized evidence from the current Store package. This confirms that the system-wide DWM bottleneck is still present on a build newer than the ones above, while also showing that a short total-handle test does not reproduce the lifetime signature every time.

Environment

  • Codex/ChatGPT Store package: OpenAI.Codex_26.818.5229.0_x64
  • Chromium/FileVersion: 151.0.7922.170
  • Windows 11 x64, build 26200, 24 logical processors, 96 GiB RAM
  • Intel Core Ultra 9 285K; NVIDIA RTX 5090, driver 32.0.16.1088
  • Dell S2425HSM, 1920x1080; reproduced at 143.85 Hz and still observable at 60 Hz
  • HAGS enabled (HwSchMode=2); no OverlayTestMode MPO override

The symptom is Windows-wide window-drag/input stutter, not merely a slow Codex window. It persisted with substantial CPU/RAM headroom and low GPU, disk, DPC, and interrupt activity. It also reproduced at 144 Hz after the emulator device process had exited, so the emulator is not a necessary condition.

WPR/ETW evidence on 26.818.5229.0

I captured the affected drag interval with the Microsoft CPU.Verbose + DesktopComposition.Light WPR profiles, then decoded it with WPA/Xperf. The analysis interval was restricted to the actual 21.5-second drag action (0.5-22.0 s), excluding trace-save work.

  • The system retained 85.93% of total CPU capacity as Idle.
  • dwm.exe averaged 0.99 logical core.
  • One DWM frame thread accounted for 85.50% of DWM sampled CPU; 87.10% of that thread's exclusive samples were in dwmcore.dll.
  • DWM Ready time averaged 8.73 us; sustained scheduler starvation was not present.
  • NVIDIA user-mode/kernel modules were only 1.96% / 0.57% of that DWM frame thread. GPU work was not saturated, and no third-party display/overlay module appeared in the hot path.
  • The three principal Codex ChatGPT.exe processes together averaged about 0.56 logical core; no single Codex process saturated a core.

An earlier lossless DesktopComposition.Light capture over an 18.482-second DWM root region showed:

  • ProcessFrame: 14.097 s
  • Present: 7.477 s
  • Occlusion: 4.169 s
  • PreCompute: 2.935 s
  • VSyncDPC: 142.35/s, matching the 143.85 Hz display mode

This independently matches the DWM-side CPU shape reported above: the user-visible failure is a serial composition/frame-thread bottleneck while the rest of the machine remains mostly idle.

Mitigation A/B

Disabling “Show window contents while dragging” at 144 Hz reduced:

  • DWM average CPU: 169.67% -> 76.93% on a one-core-equals-100% scale (-54.7%)
  • Codex/ChatGPT CPU: 45.21% -> 16.35% (-63.8%)
  • Context switches: 190,638/s -> 43,261/s (-77.3%)

This is a useful workaround, not a fix: DWM still remained around 0.77 core, and the user must give up live window contents. Reducing the display to 60 Hz also improves usability but does not eliminate the DWM bottleneck.

Short handle control on the current build

I also ran two controlled five-terminal-call batches while sampling DWM's total handle count:

  • Stable 20-second baseline: 2392 -> 2391 (range 2391-2394)
  • The first batch produced a transient rise (up to about +45 versus baseline), followed by recovery toward 2395
  • During a second 75-second time-series, the five calls produced no persistent step; the count fell from 2424 to 2395 and remained there through the end
  • DWM working set/private memory stayed near 811 / 674 MiB during this short test

This test did not enumerate the Composition handle type, so it does not disprove the typed per-runner leak documented in the comments above. It does show that the short-run total-handle signature is state-dependent on 26.818.5229.0, while the DWM frame-thread performance failure remains reproducible.

Request

Please keep investigating this against the current Windows desktop package rather than treating it as limited to the older builds. I retained the original 1.71 GiB CPU+composition ETL and sanitized WPA/Xperf exports locally. I have not attached the raw ETL because it contains a wider process timeline. If maintainers provide a privacy-safe upload route and specify the desired provider/keyword set, I can supply the trace or repeat a targeted capture.

MangelSpec · 23 hours ago

How is this issue not considered a _very_ high priority yet? I installed the app for the first time and genuinely thought something was wrong with my PC because the entire Windows desktop became increasingly unusable after only a few hours, even when closing every software (including GPT).
After finding this thread, I’m pretty shocked to see reports going back this far without any visible indication that the issue has been elevated.
In my case, restarting dwm.exe immediately fixes the system-wide lag, while Codex can remain open. CPU, GPU and memory usage are all low. The apparent handle/composition-resource leak also means the problem is accumulating long before the desktop becomes noticeably unusable.
I also asked several friends who use the Windows app, and every single one of them confirmed experiencing the same degradation.
This makes the Windows app effectively unusable for me and seriously makes me consider uninstalling it again. Is this being actively investigated / treated as a high-priority issue?