Skip to content

Fix retained screen-capture surfaces and bound image concurrency - #10

Open
pick7 wants to merge 1 commit into
witchan:mainfrom
pick7:fix-screen-memory-management
Open

Fix retained screen-capture surfaces and bound image concurrency#10
pick7 wants to merge 1 commit into
witchan:mainfrom
pick7:fix-screen-memory-management

Conversation

@pick7

@pick7 pick7 commented Aug 9, 2026

Copy link
Copy Markdown

Summary

Repeated screenshot and OCR requests could retain IOSurface-backed capture images inside SpringBoard, causing memory usage to grow continuously.

This change:

  • Corrects ARC ownership metadata for retained screen-capture images.
  • Moves the legacy re-encode capture path to the final fallback position.
  • Adds autorelease boundaries around request handling, capture, and JPEG encoding.
  • Releases the original full-resolution OCR image after creating an independent downsampled image.
  • Limits concurrent image-processing tasks to reduce transient memory pressure.
  • Adds a setting for one or two concurrent screen tasks, defaulting to one.

The public MCP tool schemas, screenshot format, and point-space coordinate metadata remain unchanged. Existing capture fallbacks are retained.

Build environment

  • macOS 26.3.1
  • Xcode 26.6
  • Apple Clang 21.0.0
  • iPhoneOS 16.5 SDK
  • roothide/theos commit 88506b2c22e9e07dd4ed055f23c9e398a117a2c7
  • Rootless arm64 and arm64e targets

Both the tweak and preference bundle compiled successfully.

Runtime environment

  • iOS 16.3.1
  • Dopamine 2.4.9
  • Rootless jailbreak

Runtime validation was performed on this environment. Other iOS versions were not runtime-tested, but the existing fallback paths remain available.

Test procedure

  1. Restart SpringBoard and record its initial footprint.
  2. Run 50 sequential screenshot requests.
  3. Run 20 sequential ocr_screen requests.
  4. Run 12 mixed screenshot/OCR requests from four client workers.
  5. Wait 30 seconds and record the retained footprint.
  6. Record SpringBoard memory using /usr/bin/footprint after each phase.

Memory observations

Phase 1.2.3 Patched
Initial 60 MB 63 MB
After 50 screenshots 595 MB 67 MB
After 20 OCR requests 843 MB 104 MB
After mixed workload 970 MB 107 MB
After 30 seconds idle 967 MB 102 MB
Peak footprint 1,040 MB 144 MB

All 82 requests completed successfully in both runs.

The IOSurface category reached approximately 861 MB on 1.2.3. With the patch, it remained at 896 KB throughout the full test.

Isolation check

A build containing only autorelease boundaries, OCR cleanup, and concurrency limiting still grew from 60 MB to 171 MB after ten screenshots, with IOSurface reaching 106 MB.

After adding the capture ownership correction, the same ten-request test changed from 61 MB to 67 MB and returned to 63-64 MB after idle, while IOSurface remained at 896 KB.

Concurrency trade-off

With the default limit of one screen task, mixed four-worker latency increased from 1.397 seconds to 2.429 seconds on average. Screenshot and sequential OCR latency remained effectively unchanged.

Devices with more available memory can select two concurrent screen tasks in Settings.

@witchan

witchan commented Aug 13, 2026

Copy link
Copy Markdown
Owner

Thanks for digging into this and sharing the test results. The NS_RETURNS_RETAINED change looks like the actual fix for the leak.

I’d rather keep this PR focused on that. Screenshot work is already serialized on the main queue, so I don’t think we need another semaphore or a user-facing concurrency setting here. Those changes also add latency and a new timeout, so they’d be better discussed in a separate PR.

Same for changing the screenshot fallback order — it may be a useful optimization, but it changes the capture path and needs its own compatibility testing.

Could you keep this PR to the ownership fix and the small cleanup changes? If possible, please also rerun the memory test with only the ownership fix enabled, just to confirm that it fixes the leak by itself.

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.

2 participants