Skip to content

cherry-pick(worklets-0.9-stable): tie RNR remote function lifetime to TurboModule invalidate status (#9789)#9898

Open
tjzel wants to merge 1 commit into
worklets-0.9-stablefrom
@tjzel/worklets-0.9-stable/cherry-pick-#9789
Open

cherry-pick(worklets-0.9-stable): tie RNR remote function lifetime to TurboModule invalidate status (#9789)#9898
tjzel wants to merge 1 commit into
worklets-0.9-stablefrom
@tjzel/worklets-0.9-stable/cherry-pick-#9789

Conversation

@tjzel

@tjzel tjzel commented Jul 7, 2026

Copy link
Copy Markdown
Collaborator

Cherry-picking #9789

This fixes memory leak that is present on the 0.9 branch, introduced in #9272

…date status (#9789)

## Summary

Fixes #9751

Changing (again) how RN Runtime remote functions (RFs) are managed,
since changes from #9673 and #9272 were actually insufficient and the
map approach won't work.

It's impossible to keep both the actual callback and cached serialized
callback value alive without a memory cycle, so I'm dropping cache
consistency. This might result in multiple serializations of a given RF
the GC triggered and the serialized value wasn't saved, but the
serialization of a RF is actually cheap.

I'm dropping the map approach entirely in favor of the behavior where
destructor invocation is based upon the information if the runtime is
still alive. We can't directly check it, so I'm depending on the
`invalidate()` method of Turbo Modules - which is supposed to be called
when the runtime is still alive.

## Test plan

You can test it on
[df3e344](df3e344)
commit - there's a special registry there that artificially extends the
lifetime of Remote Functions - click some buttons on the provided
example, then reload the app with R button. The callbacks with persist
and will crash on destructor invocation without the check for `isDead`.

(cherry picked from commit 325a644)
@tjzel tjzel marked this pull request as ready for review July 7, 2026 15:30
@tjzel tjzel requested a review from Copilot July 7, 2026 15:30

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Cherry-picks the fix from #9789 onto the 0.9 branch to address a Remote Function (RN Runtime) lifetime/memory issue by tying cleanup behavior to TurboModule invalidation (runtime “alive/dead” status), instead of maintaining a JS-side registry/map.

Changes:

  • Remove the JS-side remote function registry/id-based model (and the functionId plumbing) in favor of holding the RN-runtime jsi::Function directly on the native side.
  • Introduce RNRuntimeStatus and propagate it through module proxies so Remote Function destruction can safely avoid touching torn-down runtime state after invalidate().
  • Adjust JS-side serializable cache behavior to optionally use WeakRef (when available) to reduce retention/leak risk.

Reviewed changes

Copilot reviewed 20 out of 21 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
packages/react-native-worklets/src/WorkletsModule/workletsModuleProxy.ts Removes functionId from the proxy API for non-worklet function serialization.
packages/react-native-worklets/src/WorkletsModule/NativeWorklets.native.ts Updates wrapper to match the new 2-arg native method signature.
packages/react-native-worklets/src/privateGlobals.d.ts Removes the global __remoteFunctionRegistry type declaration.
packages/react-native-worklets/src/memory/types.ts Removes RegisteredRemoteFunction type related to the old keep-alive model.
packages/react-native-worklets/src/memory/serializableMappingCache.native.ts Allows caching WeakRef<SerializableRef> in addition to strong refs/flag.
packages/react-native-worklets/src/memory/serializable.native.ts Drops registry/id usage and uses WeakRef-based caching when available.
packages/react-native-worklets/src/memory/remoteFunctionRegistry.native.ts Deletes the JS-side remote function registry implementation.
packages/react-native-worklets/Common/cpp/worklets/Tools/RNRuntimeStatus.h Adds runtime liveness tracking used to gate Remote Function destruction behavior.
packages/react-native-worklets/Common/cpp/worklets/SharedItems/SerializableFactory.h Changes RN-runtime RF factory to accept a jsi::Function + RNRuntimeStatus.
packages/react-native-worklets/Common/cpp/worklets/SharedItems/SerializableFactory.cpp Implements new RN-runtime RF factory that stores the function directly.
packages/react-native-worklets/Common/cpp/worklets/SharedItems/Serializable.h Refactors SerializableRemoteFunction storage to use function_ + runtime status.
packages/react-native-worklets/Common/cpp/worklets/SharedItems/Serializable.cpp Updates RF destructor and toJSValue to use direct function storage and status checks.
packages/react-native-worklets/Common/cpp/worklets/NativeModules/WorkletsModuleProxy.h Threads RNRuntimeStatus through the proxy API/state.
packages/react-native-worklets/Common/cpp/worklets/NativeModules/WorkletsModuleProxy.cpp Passes RNRuntimeStatus into the RN runtime proxy instance.
packages/react-native-worklets/Common/cpp/worklets/NativeModules/JSIWorkletsModuleProxy.h Stores RNRuntimeStatus for use when creating RN-runtime remote functions.
packages/react-native-worklets/Common/cpp/worklets/NativeModules/JSIWorkletsModuleProxy.cpp Updates createSerializableNonWorkletFunction to 2 args and new RF factory call.
packages/react-native-worklets/apple/worklets/apple/WorkletsModule.mm Creates RNRuntimeStatus on install and marks it dead during invalidate.
packages/react-native-worklets/android/src/no-networking/com/swmansion/worklets/WorkletsModule.kt Removes outdated invalidate rationale comment (no functional change).
packages/react-native-worklets/android/src/networking/com/swmansion/worklets/WorkletsModule.kt Removes outdated invalidate rationale comment (no functional change).
packages/react-native-worklets/android/src/main/cpp/worklets/android/WorkletsModule.h Stores RNRuntimeStatus in the Android hybrid module.
packages/react-native-worklets/android/src/main/cpp/worklets/android/WorkletsModule.cpp Creates and marks RNRuntimeStatus dead on invalidateCpp().

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread packages/react-native-worklets/src/memory/serializable.native.ts
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants