## Objective Closing a GPUI window on macOS does not release that window's native view tree, so every open/close cycle leaves a `GPUIView`, its `CAMetalLayer` and the renderer's command queue alive in the process. A long-running app that opens and closes windows grows without bound; this is the mechanism described in #50737. The reason is a retain cycle: ``` MacWindowState -> accesskit_adapter (crates/gpui_macos/src/window.rs:710) -> NSWindow.contentView (strongly retained by accesskit_macos) -> GPUIView (a subview of that content view) -> Arc<Mutex<MacWindowState>> in its ivar (back to the start) ``` `accesskit_macos::SubclassingAdapter::for_window` keeps a strong `Id<NSView>` of the window's content view, and both the `NSWindow` and the `GPUIView` store an `Arc<Mutex<MacWindowState>>` in their `windowState` ivar. `MacWindow::drop` resets the delegate and tears down the frame source and the visibility callback, but nothing drops the adapter, so the native view tree outlives the window. Worth noting while reading the existing teardown: `gpui_apple::metal_renderer::destroy()` is currently a no-op (`crates/gpui_apple/src/metal_renderer.rs`), so the `renderer.destroy()` call that is already there is not evidence that GPU-side resources were released — what matters is whether the state that owns the renderer can run its destructor at all. ## Solution One line in `MacWindow::drop`: ```rust let mut this = self.0.lock(); drop(this.accesskit_adapter.take()); this.renderer.destroy(); ``` Nothing else in the teardown changes: - `frame_source.take()` stays. `WindowFrameSource`'s `Drop` cancels `frame_requests`, and that dispatch source's context points at the native view, so it has to be cancelled while the view is still valid. - `visibility_callback.take()` stays, as do the sheet handling and the delegate reset. - No view or layer is released by hand. The native view is already handed to its parent view via `autorelease`; the problem is the cycle, not the ownership. ## Testing Done locally on macOS (aarch64), with `stable`: - `cargo fmt -p gpui_macos -- --check` — clean. - `cargo test -p gpui_macos --lib` — 7 passed, 0 failed. - `cargo clippy -p gpui_macos --release --all-targets --all-features -- --deny warnings` — clean. Note: the adapter is only created when Zed runs with `ZED_EXPERIMENTAL_A11Y=1`, so the leak only affects that path and the fix is a no-op otherwise. What isn't covered: - **No automated test.** The cycle needs a real `NSWindow`/`contentView` pair, and the change is a `Drop` impl; a unit test here would be testing `NSView` ownership rather than this crate's logic. `gpui_macos` has no window-lifecycle test harness today, and adding one is more than this fix should carry. - **No memory measurement by me.** I did not run Instruments/`Allocations` against this change, and the minimal-repro numbers quoted in #50737 were measured on a different fork revision, not this one. So the leak here is established from the ownership graph above rather than from a footprint curve I produced. The follow-up that would settle it is a before/after count of live `GPUIView` / `CAMetalLayer` / command-queue objects after closing a window, with accessibility enabled and disabled; I have not run that, and I am not claiming this explains every memory-growth report. - Only the macOS backend is touched, so there is nothing Windows/Linux-specific here. ## Self-Review Checklist: - [x] I've reviewed my own diff for quality, security, and reliability - [x] Unsafe blocks (if any) have justifying comments - [x] The content adheres to Zed's UI standards (UI/UX and icon guidelines) — no UI change - [ ] Tests cover the new/changed behavior — not applicable, see "What isn't covered" - [x] Performance impact has been considered and is acceptable ## AI disclosure Built with substantial LLM assistance: I had help reading the `accesskit_macos` and `gpui_macos` ownership graph and drafting this description, and I reviewed every line of the diff myself. The change is one line plus a comment. English isn't my first language, so the prose here was machine-polished; happy to restate anything in plain terms. --- Release Notes: - [GPUI] Fixed a memory leak on macOS where closing a window with accessibility enabled left its native view, `CAMetalLayer` and the renderer's resources alive. - Fixed a memory leak on macOS where closing a window left its native view, `CAMetalLayer` and the renderer's resources alive.
Zed
Welcome to Zed, a high-performance, multiplayer code editor from the creators of Atom and Tree-sitter.
Installation
On macOS, Linux, and Windows you can download Zed directly or install Zed via your local package manager (macOS/Linux/Windows).
Other platforms are not yet available:
- Web (tracking discussion)
Developing Zed
Contributing
See CONTRIBUTING.md for ways you can contribute to Zed.
Also... we're hiring! Check out our jobs page for open roles.
Licensing
Zed source code is licensed primarily under GPL-3.0-or-later, with Apache-2.0 components where marked.
License information for third party dependencies must be correctly provided for CI to pass.
We use cargo-about to automatically comply with open source licenses. If CI is failing, check the following:
- Is it showing a
no license specifiederror for a crate you've created? If so, addpublish = falseunder[package]in your crate's Cargo.toml. - Is the error
failed to satisfy license requirementsfor a dependency? If so, first determine what license the project has and whether this system is sufficient to comply with this license's requirements. If you're unsure, ask a lawyer. Once you've verified that this system is acceptable add the license's SPDX identifier to theacceptedarray inscript/licenses/zed-licenses.toml. - Is
cargo-aboutunable to find the license for a dependency? If so, add a clarification field at the end ofscript/licenses/zed-licenses.toml, as specified in the cargo-about book.
Sponsorship
Zed is developed by Zed Industries, Inc., a for-profit company.
If you’d like to financially support the project, you can do so via GitHub Sponsors. Sponsorships go directly to Zed Industries and are used as general company revenue. There are no perks or entitlements associated with sponsorship.