Skip to content

feat(ui): wire GC pump-step + OS memory-pressure into non-macOS hosts (#6183, #6184)#6210

Merged
proggeramlug merged 1 commit into
mainfrom
feat/ui-gc-platform-integration
Jul 9, 2026
Merged

feat(ui): wire GC pump-step + OS memory-pressure into non-macOS hosts (#6183, #6184)#6210
proggeramlug merged 1 commit into
mainfrom
feat/ui-gc-platform-integration

Conversation

@proggeramlug

@proggeramlug proggeramlug commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Extends the GC embedder integration already merged for the macOS host to the
remaining UI hosts. Two runtime FFIs land on main already; this wires the
host-side calls. Reference: #6183 #6184; 2026-07-09 GC audit.

A. Pump GC-step (#6183)

Mirrors the merged macOS pump call: js_gc_step_us(2_000, null) in each host's
run-loop / timer pump tail. That point is a precise-root safepoint (the JS
stack is fully unwound), so an active budgeted GC cycle drains in bounded 2ms
slices instead of an unbounded alloc-point collection landing on the UI thread
mid-interaction. Extern declared per host, matching the macOS style.

Host Pump site
iOS PerryPumpTarget::pump: (perry-ui-ios/src/app.rs)
tvOS PerryPumpTarget::pump: (perry-ui-tvos/src/app.rs)
visionOS PerryPumpTarget::pump: (perry-ui-visionos/src/app.rs)
watchOS SwiftUI render Timer in PerryWatchApp.swift (@_silgen_name FFI)
gtk4 glib::timeout_add_local pump closure (perry-ui-gtk4/src/app.rs)
Windows Win32 message-loop TIMER_TICK_NEEDED block (perry-ui-windows/src/app.rs)
Android nativePumpTick JNI callback (perry-ui-android/src/app.rs)

B. OS memory-pressure (#6184)

Forwards the platform signal to js_gc_memory_pressure(level) (1 = minor,
2 = full collect + trigger clamp).

  • iOS / tvOS — added applicationDidReceiveMemoryWarning: to the Rust
    PerryAppDelegate (define_class!), calling js_gc_memory_pressure(2) (a
    UIKit memory warning is the last notice before jetsam → critical).
  • visionOS — the SwiftUI host has no app-delegate memory callback, so
    PerryVisionBootstrap observes UIApplication.didReceiveMemoryWarningNotification
    on the main queue → level 2.
  • macOS — new memory_pressure.rs installs a
    DISPATCH_SOURCE_TYPE_MEMORYPRESSURE source on the main queue at app_run:
    WARN → 1, CRITICAL → 2. libdispatch symbols bound directly (part of
    libSystem; no new crate). This is the one macOS piece that wasn't done yet.
  • AndroidPerryActivity.onLowMemory() → 2; new onTrimMemory(level)
    override maps TRIM_MEMORY_RUNNING_CRITICAL | COMPLETE | MODERATE → 2 and
    lighter trims → 1 (constants aren't monotonic by severity, so the severe set
    is matched explicitly). Wired via a new nativeMemoryPressure JNI shim
    (perry-ui-android/src/lib.rs) + Kotlin external fun (PerryBridge.kt),
    guarded against UnsatisfiedLinkError for warnings that arrive pre-init. The
    existing Google-Maps forwardMapsLifecycle("lowMemory") is preserved.

Out of scope

  • Linux PSI polling for gtk4 — a server concern, deliberately not added.
  • Windows / gtk4 OS memory-pressure — no in-scope UI memory signal was
    wired (only the pump-step). Notable as remaining if desired later
    (WM_COMPACTING / QueryMemoryResourceNotification on Windows).

Build verification

Verified with target-specific cargo check where the toolchain is present;
inspection-only where a cross native-toolchain is missing on this macOS host
(honest status — no fabricated builds):

Host Build-verified?
macOS cargo check -p perry-ui-macos — PASS (includes dispatch-source module)
iOS cargo check --target aarch64-apple-ios — PASS
tvOS cargo check --target aarch64-apple-tvos — PASS
visionOS cargo check --target aarch64-apple-visionos — PASS (Rust; Swift template inspection-only)
watchOS Rust crate PASS; the change is Swift-only (PerryWatchApp.swift), inspection-only
gtk4 inspection-only — cross-compile blocked (glib-sys pkg-config can't cross-compile)
Windows inspection-only — cross-compile blocked (libmimalloc-sys needs a Windows C++ toolchain)
Android inspection-only — cross-compile blocked (aarch64-linux-android-clang NDK not installed); Kotlin inspection-only

cargo fmt --all -- --check passes.

Summary by CodeRabbit

  • New Features
    • Added improved memory-pressure handling across supported platforms, helping the app respond more quickly to low-memory situations.
    • Added incremental background runtime cleanup during regular UI/update cycles to spread work into small bounded steps.
  • Bug Fixes
    • Reduced the chance of sudden performance spikes by avoiding larger cleanup bursts during normal app activity.
    • Improved stability when the operating system sends memory warning signals.

…#6183, #6184)

Extend the GC embedder integration (already merged for macOS) to the other UI
hosts. 2026-07-09 GC audit.

Pump GC-step (#6183): call js_gc_step_us(2_000, null) in each host's run-loop /
timer pump tail — a precise-root safepoint where the JS stack is unwound — so
an active budgeted GC cycle drains in bounded 2ms slices instead of an
unbounded alloc-point collection landing on the UI thread mid-interaction:
  - iOS / tvOS / visionOS: PerryPumpTarget pump: (extern block + call)
  - gtk4: glib timeout pump closure
  - Windows: Win32 message-loop timer-tick block
  - Android: nativePumpTick JNI callback
  - watchOS: SwiftUI render Timer (Swift @_silgen_name FFI)

OS memory-pressure (#6184): forward the platform signal to js_gc_memory_pressure
(1 = minor, 2 = full collect + trigger clamp):
  - iOS / tvOS: PerryAppDelegate applicationDidReceiveMemoryWarning: -> 2
  - visionOS: SwiftUI host observes UIApplication.didReceiveMemoryWarning -> 2
  - macOS: new memory_pressure.rs installs a DISPATCH_SOURCE_TYPE_MEMORYPRESSURE
    source on the main queue at app_run (WARN -> 1, CRITICAL -> 2)
  - Android: PerryActivity.onLowMemory -> 2 and new onTrimMemory(level) mapping
    (RUNNING_CRITICAL / COMPLETE / MODERATE -> 2, lighter trims -> 1) via a new
    nativeMemoryPressure JNI shim + Kotlin external fun

Linux PSI polling for gtk4 is intentionally out of scope (a server concern).
@coderabbitai

coderabbitai Bot commented Jul 9, 2026

Copy link
Copy Markdown

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 819b9ec9-1632-42c8-8865-9947996c0559

📥 Commits

Reviewing files that changed from the base of the PR and between d9500be and 27a2c4a.

📒 Files selected for processing (14)
  • crates/perry-ui-android/src/app.rs
  • crates/perry-ui-android/src/lib.rs
  • crates/perry-ui-android/template/app/src/main/java/com/perry/app/PerryActivity.kt
  • crates/perry-ui-android/template/app/src/main/java/com/perry/app/PerryBridge.kt
  • crates/perry-ui-gtk4/src/app.rs
  • crates/perry-ui-ios/src/app.rs
  • crates/perry-ui-macos/src/app.rs
  • crates/perry-ui-macos/src/lib.rs
  • crates/perry-ui-macos/src/memory_pressure.rs
  • crates/perry-ui-tvos/src/app.rs
  • crates/perry-ui-visionos/src/app.rs
  • crates/perry-ui-visionos/swift/PerryVisionApp.swift
  • crates/perry-ui-watchos/swift/PerryWatchApp.swift
  • crates/perry-ui-windows/src/app.rs

📝 Walkthrough

Walkthrough

This PR adds a bounded embedder GC step (js_gc_step_us, 2ms budget) invoked at each UI pump tick across Android, GTK4, iOS, tvOS, visionOS, watchOS, and Windows, and wires OS memory-pressure signals (Android JNI, iOS/tvOS memory warnings, macOS libdispatch source, visionOS notifications) into js_gc_memory_pressure.

Changes

Embedder GC pump-step and memory-pressure wiring

Layer / File(s) Summary
Android GC step and memory pressure
crates/perry-ui-android/src/app.rs, crates/perry-ui-android/src/lib.rs, crates/perry-ui-android/template/.../PerryActivity.kt, crates/perry-ui-android/template/.../PerryBridge.kt
Adds js_gc_step_us call in the pump tick, a nativeMemoryPressure JNI bridge, and Kotlin onLowMemory/onTrimMemory handlers forwarding memory pressure levels.
GTK4 pump GC step
crates/perry-ui-gtk4/src/app.rs
Adds js_gc_step_us FFI declaration and a bounded step call in the main pump tick callback.
iOS memory warning and pump GC step
crates/perry-ui-ios/src/app.rs
Adds applicationDidReceiveMemoryWarning: handler, js_gc_step_us/js_gc_memory_pressure FFI bindings, and a per-tick GC step in PerryPumpTarget.
macOS libdispatch memory-pressure source
crates/perry-ui-macos/src/lib.rs, crates/perry-ui-macos/src/memory_pressure.rs, crates/perry-ui-macos/src/app.rs
Adds a new memory_pressure module installing a libdispatch source that maps WARN/CRITICAL flags to js_gc_memory_pressure calls, wired into app_run startup.
tvOS memory warning and pump GC step
crates/perry-ui-tvos/src/app.rs
Adds applicationDidReceiveMemoryWarning: handler and a bounded js_gc_step_us call in the pump loop.
visionOS pump GC step and memory warning
crates/perry-ui-visionos/src/app.rs, crates/perry-ui-visionos/swift/PerryVisionApp.swift
Adds js_gc_step_us pump invocation in Rust and a Swift memory warning observer calling js_gc_memory_pressure.
watchOS pump GC step
crates/perry-ui-watchos/swift/PerryWatchApp.swift
Adds js_gc_step_us FFI declaration and a per-frame GC step call in PerryBridge.start().
Windows pump GC step
crates/perry-ui-windows/src/app.rs
Adds js_gc_step_us FFI declaration and a bounded GC step call in TIMER_TICK_NEEDED handling.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Possibly related issues

Possibly related PRs

  • PerryTS/perry#5973: Both PRs modify the watchOS PerryWatchApp.swift per-frame PerryBridge.start() tick logic, with this PR adding an additional js_gc_step_us call in the same timer boundary.
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the GC pump-step and memory-pressure wiring across UI hosts, though it omits the macOS memory-pressure addition.
Description check ✅ Passed The description is detailed and on-topic, covering summary, changes, related issues, and verification, though it does not follow the repository template exactly.
Docstring Coverage ✅ Passed Docstring coverage is 80.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/ui-gc-platform-integration

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@proggeramlug proggeramlug merged commit 5a58be5 into main Jul 9, 2026
25 checks passed
@proggeramlug proggeramlug deleted the feat/ui-gc-platform-integration branch July 9, 2026 21:21
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