Closed windows never release their Metal layer, IOSurfaces, or on_window_should_close closure (macOS, gpui-pre 0.3.4)

Author: felipefdlCreated Sep 12, 2026Updated Sep 12, 2026

Every window.remove_window() on macOS leaks the platform window's GPU state. Measured with a release build of an app that opens one window per document, repeating open-then-close five times and inspecting the process with vmmap --summary and heap after each cycle:

cycle RSS IOSurface IOAccelerator (graphics) CAMetalLayer objects alive
0 windows, after first close 112 MB 21 MB 4 MB 1
1 156 MB 43 MB 22 MB 2
2 190 MB 64 MB 39 MB 3
5 290 MB 117 MB 90 MB 6

With zero windows open, heap still lists one CAMetalLayer, two IOSurfaces and a NSWindowAuxiliary per closed window. An empty window (a single div) leaks about 25 MB per open/close cycle, so it is not content related.

Second, Window::on_window_should_close boxes the caller's closure into the platform window. Because that platform window is retained, anything the closure captures is retained too. A strong Entity<View> captured there keeps the whole view tree alive after close; in our case that was ~17 MB of decoded image per document. Downgrading to WeakEntity on the app side works around that part, but the surfaces still leak.

Repro: run any example that opens a window, close it, run heap <pid> | grep -E 'CAMetalLayer|IOSurface'; repeat.

Environment: macOS 27.0, Apple M4 Pro, gpui-kit 0.6.1 / gpui-pre 0.3.4.

Measured on https://github.com/felipefdl/openit (one window per document).

Source: longbridge/gpui-component