Skip to content

Release the props map local reference in synchronouslyUpdateViewOnUIThread - #59696

Open
tomekzaw wants to merge 1 commit into
react:mainfrom
tomekzaw:fix-sync-update-local-ref
Open

tomekzaw wants to merge 1 commit into
react:mainfrom
tomekzaw:fix-sync-update-local-ref

Conversation

@tomekzaw

@tomekzaw tomekzaw commented Oct 30, 2026 •

Copy link
Copy Markdown
Contributor

Summary:

FabricMountingManager::synchronouslyUpdateViewOnUIThread creates a ReadableNativeMap for the props and calls .release() on its local reference, so nothing deletes it. The C++ animation backend calls this once per animated view on every frame: for every view when optimizedAnimatedPropUpdates is off, and for views with layout updates otherwise. So each props map stays alive until the frame callback returns to Java. A frame that animates 600 views holds 600 local references. Android 7, the oldest supported version, limits a thread to 512 local references and aborts above that.

This wraps the reference in jni::adopt_local, like dispatchCommand above it, so each map is released after its call.

Changelog:

[ANDROID] [FIXED] - Release the JNI local reference to the props map in synchronouslyUpdateViewOnUIThread

Test Plan:

Release RNTester (./gradlew :packages:rn-tester:android:app:assembleRelease -PreactNativeArchitectures=arm64-v8a) with these temporary, uncommitted changes:

  • The experimental release level, so cxxNativeAnimatedEnabled and useSharedAnimatedBackend are on and optimizedAnimatedPropUpdates is off.
  • A Playground screen that animates the translateX of 600 views with useNativeDriver: true.
  • Logging that records the slot of a fresh local reference at the start of each synchronouslyUpdateViewOnUIThread call.

On a Galaxy A16 (Android 16):

Calls per frame Distinct local reference slots
main 600 600
This PR 600 1

On main, every call starts on a new slot because the earlier maps are still referenced. With this change, every call reuses the same slot.

Performance, with the same setup (600 views moved by one native-driven animation), timed per animation frame (Java timer around driveAnimationBackend, which includes freeing the local references when it returns) and per synchronouslyUpdateViewOnUIThread call (C++ timer):

Galaxy A16 Pixel 9a OPPO CPH2269 moto g57 power
One animation frame 40.27 ms → 40.40 ms (no change) 10.70 ms → 10.73 ms (no change) 119.21 ms → 118.06 ms (no change) 26.27 ms → 26.45 ms (no change)
One synchronouslyUpdateViewOnUIThread call 54.00 µs → 54.00 µs (no change) 12.21 µs → 12.23 µs (no change) 145.12 µs → 142.96 µs (no change) 33.12 µs → 33.49 µs (no change)

Setup:

  • Release RNTester with R8 on and the experimental release level, compiled with cmd package compile -m speed.
  • Temporary timing probes, not part of this PR, and a Playground scenario opened by deep link.
  • Each run is a fresh process: a 12 s window after the scenario starts, reported as the median of its samples. Per phone, one discarded run of each build, then 8 A/B/B/A cycles of main and this PR (16 processes per build).
  • Each figure is the median of the 16 processes. "No change" means the 95% bootstrap confidence interval includes zero. It is within about ±2% on the Galaxy A16, Pixel 9a and moto g57 power. The OPPO CPH2269 is noisier (about 120 ms per frame, so few samples per run).
  • The Galaxy A16, Pixel 9a and moto g57 power run Android 16. The OPPO CPH2269 runs Android 11.

Not run: Android 7, where the 512-reference limit would turn this into a crash; I don't have a device with it.

🤖 Generated with Claude Code

…hread

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@meta-cla meta-cla Bot added the CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. label Oct 30, 2026
@facebook-github-tools facebook-github-tools Bot added p: Software Mansion Partner: Software Mansion Partner labels Oct 30, 2026
@tomekzaw
tomekzaw marked this pull request as ready for review October 30, 2026 22:03
@facebook-github-tools facebook-github-tools Bot added the Shared with Meta Applied via automation to indicate that an Issue or Pull Request has been shared with the team. label Oct 30, 2026
@meta-codesync

meta-codesync Bot commented Oct 30, 2026

Copy link
Copy Markdown

@javache has imported this pull request. If you are a Meta employee, you can view this in D128714083.

@tomekzaw
tomekzaw force-pushed the fix-sync-update-local-ref branch from 12d3a34 to 6873b79 Compare November 2, 2026 17:00

This branch has not been deployed

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

Labels

CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. p: Software Mansion Partner: Software Mansion Partner Shared with Meta Applied via automation to indicate that an Issue or Pull Request has been shared with the team.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants