Skip to content

fix: drain autoreleased objects in the macOS tray - #159

Open
jremick wants to merge 1 commit into
reason-machines:mainfrom
jremick:fix/macos-tray-autorelease
Open

jremick wants to merge 1 commit into
reason-machines:mainfrom
jremick:fix/macos-tray-autorelease

Conversation

@jremick

@jremick jremick commented Oct 27, 2026

Copy link
Copy Markdown

The macOS tray runs a manual AppKit event loop without draining an autorelease pool. Repeated directory updates accumulate temporary menus, images and related objects. A long-running 0.12.13 tray reached about 1 GiB of physical footprint, with 131,878 NSImage objects and 12,042 autorelease-pool pages.

This change drains a finite pool after startup and a new pool after each complete event-loop iteration. The application, tray and current menu keep their retained ownership across iterations. This follows AppKit's autorelease-pool requirements.

The new macOS regression check runs the actual tray against a private synthetic IPC directory: eight machines and 56–64 sessions, with changing connectivity, RTT, status and activity text. It measures physical footprint with vmmap, writes JSON evidence, and checks that polling continues. Its result is explicitly memory-only; the script documents a separate submenu interaction check.

Before and after

Both builds used Rust 1.99.1, the existing Cargo.lock and the debug profile on macOS 27.0.1 arm64. The baseline was built from upstream 5a6d0835868e1e648bed9144360d29455ebe8e6f. Each run had a 15-second warmup, 120 seconds of measurement and 60 measured directory polls. Menus stayed closed during measurement.

Build Initial footprint Final footprint Growth Result (4 MiB limit)
Unpatched 16.2 MiB 27.5 MiB 11.3 MiB Fails
Patched 14.9 MiB 15.4 MiB 0.5 MiB Passes

A separate patched-process stack sample observed menu creation/replacement, image drawing, objc_autoreleasePoolPop, and NSImage deallocation. Its heap contained four NSImage objects and four autorelease-pool pages at the sampled point. This supports that the main thread continued processing updates, rather than merely leaving the background poller alive.

Validation

  • cargo fmt --check
  • cargo clippy --all-targets --locked -- -D warnings
  • cargo test --locked: 254 unit tests and 2 install-script tests passed
  • python3 tests/e2e/tray_memory.py --binary <unpatched-build> --output <baseline.json>: failed for memory growth
  • python3 tests/e2e/tray_memory.py --output <fixed.json>: passed
  • Python syntax and invalid-duration argument checks
  • git diff --check

The unchanged upstream CI workflow passed on all three platforms with Rust 1.99.1: CI run.

CI platform Formatting Clippy (-D warnings) Tests
Ubuntu 24.04 Passed Passed 256 unit + 2 install-script tests passed
Windows (windows-latest) Passed Passed 245 tests passed; no install-script tests run on Windows
macOS 14 Passed Passed 254 unit + 2 install-script tests passed

The fork CI commit 7b88c2619940c7834ab0ac0f4b619d4dce7a18ab has the same Git tree as the proposed fix commit 05dd37fd5c5d666f7bbc92fe1bda501fe431b4e3. Two empty commits triggered CI after enabling Actions on the new fork; they are not part of this PR branch. No workflow files were changed in the proposed fix.

Manual submenu interaction remains unverified: the available app-control interface could not address the menu-bar-only process, including through a temporary app bundle. The measured two-minute regression is not an overnight soak test.

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 27, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ⚠️ Failed 2026-10-27T01:36:49.230043Z
We couldn’t complete this review. Comment @codex review to try again.
05dd37f PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant