Skip to content

fix: lifetime memory growth from macOS permission-check SCShareableContent polling - #2064

Merged
richiemcilroy merged 5 commits into
mainfrom
sck-permission-leak
Aug 2, 2026
Merged

fix: lifetime memory growth from macOS permission-check SCShareableContent polling#2064
richiemcilroy merged 5 commits into
mainfrom
sck-permission-leak

Conversation

@richiemcilroy

@richiemcilroy richiemcilroy commented Aug 2, 2026

Copy link
Copy Markdown
Member

Fixes #2023 (CAP-761) and the swap-exhaustion incident documented in maxktz/cap-memory-leak-incident (Cap suspended by macOS at 82.29 GB).

Since ae303ef, the screen-recording permission check ran a full `SCShareableContent` enumeration, and polling callers (5s device-snapshot emitter, UI polls, 250ms onboarding poll) drove it on tokio threads with no autorelease pool for the entire process lifetime — measured at ~138 KB leaked per call (scales with system window count), matching the reported ~15–18 MiB/min growth.

  • Cache a successful SCK display validation for the process lifetime (revocation is still caught by the cheap `CGPreflightScreenCaptureAccess` gate); throttle failed validations to one per 5s and serialise concurrent validators
  • Wrap the permission check, camera device enumeration, and display name/scale lookups in autorelease pools
  • Release the +1 `NSScreen` lookup key (leaked per screen per call) and the CoreAudio device-name `CFString` (leaked by the upstream helper, twice on its fallback path)
  • Hard-cap the mic volume meter window (frozen/non-monotonic capture clocks stalled eviction forever) and cancel the mic source's bridge tasks on drop so a wedged teardown can't pin the cpal stream

Validated: `cargo clippy -D warnings` clean on all five touched crates; 31 microphone tests pass; a probe replicating the old call pattern shows ~138 KB/call linear growth unpooled vs flat (~1 KB/call) with the fix. Note #1589 (growth while a recording is paused) is a separate report and not addressed here.

Greptile Summary

The PR addresses long-running macOS memory growth by reducing repeated ScreenCaptureKit enumeration, introducing autorelease pools and explicit native-object cleanup, and bounding or cancelling microphone-related resources.

  • Caches successful ScreenCaptureKit display validation and throttles failed attempts.
  • Adds autorelease pools around macOS permission, camera, and display metadata polling.
  • Corrects CoreAudio and AppKit native-object ownership.
  • Bounds audio-meter retention and cancels microphone bridge tasks during teardown.

Confidence Score: 5/5

The PR appears safe to merge, with no concrete changed-code defect identified.

The resource-lifetime changes preserve existing capture and permission behavior while bounding retained state, serializing expensive validation, and releasing or draining native resources at their intended ownership boundaries.

Important Files Changed

Filename Overview
apps/desktop/src-tauri/src/permissions.rs Serializes, throttles, and caches ScreenCaptureKit validation while pooling Objective-C temporaries during permission polling.
apps/desktop/src-tauri/src/audio_meter.rs Adds a 512-entry fallback bound for volume-meter timestamps when capture clocks stop advancing.
crates/camera-avfoundation/src/lib.rs Wraps AVFoundation device discovery in an autorelease pool without changing the returned retained device array.
crates/camera/src/macos.rs Materializes camera metadata inside an autorelease pool before returning owned Rust values.
crates/recording/src/feeds/microphone.rs Replaces the leaking CoreAudio device-name helper with an explicitly owned CFString lookup and adds diagnostics for deferred removal.
crates/recording/src/sources/microphone.rs Cancels detached microphone bridge tasks when their owning source is dropped.
crates/scap-targets/src/platform/macos.rs Pools display metadata lookups and releases the owned NSScreen dictionary key after use.

Reviews (1): Last reviewed commit: "fix(desktop): cap mic volume meter windo..." | Re-trigger Greptile

Context used:

@richiemcilroy
richiemcilroy marked this pull request as ready for review August 2, 2026 22:27
@cursor

cursor Bot commented Aug 2, 2026

Copy link
Copy Markdown

Bugbot is not enabled for your account, so this pull request was not reviewed.

Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs.

@richiemcilroy
richiemcilroy merged commit dba287e into main Aug 2, 2026
26 of 27 checks passed
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.

[macOS] Cap 0.5.7 leaks ~17–18 MB/min after Studio recording/editor use until quit

1 participant