Skip to content

Commit 487e091

Browse files
rozelefacebook-github-bot
authored andcommitted
Delete ShadowTreeRevision on background thread (#50997)
Summary: Pull Request resolved: #50997 In some apps, we spend a non-trivial amount of time calling ShadowNode destructors on the UI thread. A simple way to avoid stalling the UI thread is to move the `baseRevision_` instance to a data structure that is cleared on a background thread, so it's tree of ShadowNode shared_ptrs are released (and in most cases destroyed) on the background thread. Rather than using std::thread, this change introduces the LowPriorityExecutor abstraction that should be supplied by host platforms. The implementation of this LowPriorityExecutor for each platform is as follows: - iOS: uses dispatch_async to a low priority dispatch queue - Android: uses a pthread with SCHED_OTHER and priority = 19 Moving the ShadowTreeRevision into a lambda capture and punting the lambda to the LowPriorityExecutor moves the destructor calls of the ShadowNodes to the host platform implementation of the LowPriorityExecutor. This change is also guarded by a feature flag so we can keep an eye out for potential memory leaks. ## Changelog [Internal] Reviewed By: NickGerleman Differential Revision: D73688009
1 parent 69f9a9a commit 487e091

28 files changed

+360
-66
lines changed

packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlags.kt

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
* This source code is licensed under the MIT license found in the
55
* LICENSE file in the root directory of this source tree.
66
*
7-
* @generated SignedSource<<b86b8bb1d53ca03240c25adb8b423040>>
7+
* @generated SignedSource<<31638ef8ac6992a354785b74af8fbe0d>>
88
*/
99

1010
/**
@@ -90,6 +90,12 @@ public object ReactNativeFeatureFlags {
9090
@JvmStatic
9191
public fun enableCustomFocusSearchOnClippedElementsAndroid(): Boolean = accessor.enableCustomFocusSearchOnClippedElementsAndroid()
9292

93+
/**
94+
* Enables destructor calls for ShadowTreeRevision in the background to reduce UI thread work.
95+
*/
96+
@JvmStatic
97+
public fun enableDestroyShadowTreeRevisionAsync(): Boolean = accessor.enableDestroyShadowTreeRevisionAsync()
98+
9399
/**
94100
* When enabled a subset of components will avoid double measurement on Android.
95101
*/

packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsCxxAccessor.kt

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
* This source code is licensed under the MIT license found in the
55
* LICENSE file in the root directory of this source tree.
66
*
7-
* @generated SignedSource<<9c1e0e7e87aead96e2554ef5ecf9e7af>>
7+
* @generated SignedSource<<6b382661025db56592b44255f5a8694c>>
88
*/
99

1010
/**
@@ -30,6 +30,7 @@ internal class ReactNativeFeatureFlagsCxxAccessor : ReactNativeFeatureFlagsAcces
3030
private var enableBridgelessArchitectureCache: Boolean? = null
3131
private var enableCppPropsIteratorSetterCache: Boolean? = null
3232
private var enableCustomFocusSearchOnClippedElementsAndroidCache: Boolean? = null
33+
private var enableDestroyShadowTreeRevisionAsyncCache: Boolean? = null
3334
private var enableDoubleMeasurementFixAndroidCache: Boolean? = null
3435
private var enableEagerRootViewAttachmentCache: Boolean? = null
3536
private var enableFabricLogsCache: Boolean? = null
@@ -156,6 +157,15 @@ internal class ReactNativeFeatureFlagsCxxAccessor : ReactNativeFeatureFlagsAcces
156157
return cached
157158
}
158159

160+
override fun enableDestroyShadowTreeRevisionAsync(): Boolean {
161+
var cached = enableDestroyShadowTreeRevisionAsyncCache
162+
if (cached == null) {
163+
cached = ReactNativeFeatureFlagsCxxInterop.enableDestroyShadowTreeRevisionAsync()
164+
enableDestroyShadowTreeRevisionAsyncCache = cached
165+
}
166+
return cached
167+
}
168+
159169
override fun enableDoubleMeasurementFixAndroid(): Boolean {
160170
var cached = enableDoubleMeasurementFixAndroidCache
161171
if (cached == null) {

packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsCxxInterop.kt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
* This source code is licensed under the MIT license found in the
55
* LICENSE file in the root directory of this source tree.
66
*
7-
* @generated SignedSource<<b95c0d1f576b67fcf9d9df498ea30994>>
7+
* @generated SignedSource<<8276fd1166cdd235f11a0b490bb7d924>>
88
*/
99

1010
/**
@@ -48,6 +48,8 @@ public object ReactNativeFeatureFlagsCxxInterop {
4848

4949
@DoNotStrip @JvmStatic public external fun enableCustomFocusSearchOnClippedElementsAndroid(): Boolean
5050

51+
@DoNotStrip @JvmStatic public external fun enableDestroyShadowTreeRevisionAsync(): Boolean
52+
5153
@DoNotStrip @JvmStatic public external fun enableDoubleMeasurementFixAndroid(): Boolean
5254

5355
@DoNotStrip @JvmStatic public external fun enableEagerRootViewAttachment(): Boolean

packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsDefaults.kt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
* This source code is licensed under the MIT license found in the
55
* LICENSE file in the root directory of this source tree.
66
*
7-
* @generated SignedSource<<c7425e6212e4e9d70e64452e550bf638>>
7+
* @generated SignedSource<<ffadd7912aed2d95b0c6199aa8902690>>
88
*/
99

1010
/**
@@ -43,6 +43,8 @@ public open class ReactNativeFeatureFlagsDefaults : ReactNativeFeatureFlagsProvi
4343

4444
override fun enableCustomFocusSearchOnClippedElementsAndroid(): Boolean = true
4545

46+
override fun enableDestroyShadowTreeRevisionAsync(): Boolean = false
47+
4648
override fun enableDoubleMeasurementFixAndroid(): Boolean = false
4749

4850
override fun enableEagerRootViewAttachment(): Boolean = false

packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsLocalAccessor.kt

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
* This source code is licensed under the MIT license found in the
55
* LICENSE file in the root directory of this source tree.
66
*
7-
* @generated SignedSource<<5b145ee103cf6b40e13d33c88cd52777>>
7+
* @generated SignedSource<<5dc41059d71d3a345be45a6a233b05a0>>
88
*/
99

1010
/**
@@ -34,6 +34,7 @@ internal class ReactNativeFeatureFlagsLocalAccessor : ReactNativeFeatureFlagsAcc
3434
private var enableBridgelessArchitectureCache: Boolean? = null
3535
private var enableCppPropsIteratorSetterCache: Boolean? = null
3636
private var enableCustomFocusSearchOnClippedElementsAndroidCache: Boolean? = null
37+
private var enableDestroyShadowTreeRevisionAsyncCache: Boolean? = null
3738
private var enableDoubleMeasurementFixAndroidCache: Boolean? = null
3839
private var enableEagerRootViewAttachmentCache: Boolean? = null
3940
private var enableFabricLogsCache: Boolean? = null
@@ -170,6 +171,16 @@ internal class ReactNativeFeatureFlagsLocalAccessor : ReactNativeFeatureFlagsAcc
170171
return cached
171172
}
172173

174+
override fun enableDestroyShadowTreeRevisionAsync(): Boolean {
175+
var cached = enableDestroyShadowTreeRevisionAsyncCache
176+
if (cached == null) {
177+
cached = currentProvider.enableDestroyShadowTreeRevisionAsync()
178+
accessedFeatureFlags.add("enableDestroyShadowTreeRevisionAsync")
179+
enableDestroyShadowTreeRevisionAsyncCache = cached
180+
}
181+
return cached
182+
}
183+
173184
override fun enableDoubleMeasurementFixAndroid(): Boolean {
174185
var cached = enableDoubleMeasurementFixAndroidCache
175186
if (cached == null) {

packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsProvider.kt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
* This source code is licensed under the MIT license found in the
55
* LICENSE file in the root directory of this source tree.
66
*
7-
* @generated SignedSource<<9cdb965a420d53cf36b6531684cb07ae>>
7+
* @generated SignedSource<<35f6d9ae3c445c81fc4bab7509fd3179>>
88
*/
99

1010
/**
@@ -43,6 +43,8 @@ public interface ReactNativeFeatureFlagsProvider {
4343

4444
@DoNotStrip public fun enableCustomFocusSearchOnClippedElementsAndroid(): Boolean
4545

46+
@DoNotStrip public fun enableDestroyShadowTreeRevisionAsync(): Boolean
47+
4648
@DoNotStrip public fun enableDoubleMeasurementFixAndroid(): Boolean
4749

4850
@DoNotStrip public fun enableEagerRootViewAttachment(): Boolean

packages/react-native/ReactAndroid/src/main/jni/react/featureflags/JReactNativeFeatureFlagsCxxInterop.cpp

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
* This source code is licensed under the MIT license found in the
55
* LICENSE file in the root directory of this source tree.
66
*
7-
* @generated SignedSource<<c89831646046b10c7b2a40e14deb3d1a>>
7+
* @generated SignedSource<<d566c157b7db07e235bada071067f11d>>
88
*/
99

1010
/**
@@ -99,6 +99,12 @@ class ReactNativeFeatureFlagsJavaProvider
9999
return method(javaProvider_);
100100
}
101101

102+
bool enableDestroyShadowTreeRevisionAsync() override {
103+
static const auto method =
104+
getReactNativeFeatureFlagsProviderJavaClass()->getMethod<jboolean()>("enableDestroyShadowTreeRevisionAsync");
105+
return method(javaProvider_);
106+
}
107+
102108
bool enableDoubleMeasurementFixAndroid() override {
103109
static const auto method =
104110
getReactNativeFeatureFlagsProviderJavaClass()->getMethod<jboolean()>("enableDoubleMeasurementFixAndroid");
@@ -363,6 +369,11 @@ bool JReactNativeFeatureFlagsCxxInterop::enableCustomFocusSearchOnClippedElement
363369
return ReactNativeFeatureFlags::enableCustomFocusSearchOnClippedElementsAndroid();
364370
}
365371

372+
bool JReactNativeFeatureFlagsCxxInterop::enableDestroyShadowTreeRevisionAsync(
373+
facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop> /*unused*/) {
374+
return ReactNativeFeatureFlags::enableDestroyShadowTreeRevisionAsync();
375+
}
376+
366377
bool JReactNativeFeatureFlagsCxxInterop::enableDoubleMeasurementFixAndroid(
367378
facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop> /*unused*/) {
368379
return ReactNativeFeatureFlags::enableDoubleMeasurementFixAndroid();
@@ -599,6 +610,9 @@ void JReactNativeFeatureFlagsCxxInterop::registerNatives() {
599610
makeNativeMethod(
600611
"enableCustomFocusSearchOnClippedElementsAndroid",
601612
JReactNativeFeatureFlagsCxxInterop::enableCustomFocusSearchOnClippedElementsAndroid),
613+
makeNativeMethod(
614+
"enableDestroyShadowTreeRevisionAsync",
615+
JReactNativeFeatureFlagsCxxInterop::enableDestroyShadowTreeRevisionAsync),
602616
makeNativeMethod(
603617
"enableDoubleMeasurementFixAndroid",
604618
JReactNativeFeatureFlagsCxxInterop::enableDoubleMeasurementFixAndroid),

packages/react-native/ReactAndroid/src/main/jni/react/featureflags/JReactNativeFeatureFlagsCxxInterop.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
* This source code is licensed under the MIT license found in the
55
* LICENSE file in the root directory of this source tree.
66
*
7-
* @generated SignedSource<<2a5ad62d2cb4f1111391f1b566e10c1d>>
7+
* @generated SignedSource<<270b461fa199f8e6365948cded0785ad>>
88
*/
99

1010
/**
@@ -60,6 +60,9 @@ class JReactNativeFeatureFlagsCxxInterop
6060
static bool enableCustomFocusSearchOnClippedElementsAndroid(
6161
facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop>);
6262

63+
static bool enableDestroyShadowTreeRevisionAsync(
64+
facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop>);
65+
6366
static bool enableDoubleMeasurementFixAndroid(
6467
facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop>);
6568

packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlags.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
* This source code is licensed under the MIT license found in the
55
* LICENSE file in the root directory of this source tree.
66
*
7-
* @generated SignedSource<<0eb63ead191be88440cbb73fd760dec7>>
7+
* @generated SignedSource<<74f22c6a0302a9923e99d2455d84e231>>
88
*/
99

1010
/**
@@ -66,6 +66,10 @@ bool ReactNativeFeatureFlags::enableCustomFocusSearchOnClippedElementsAndroid()
6666
return getAccessor().enableCustomFocusSearchOnClippedElementsAndroid();
6767
}
6868

69+
bool ReactNativeFeatureFlags::enableDestroyShadowTreeRevisionAsync() {
70+
return getAccessor().enableDestroyShadowTreeRevisionAsync();
71+
}
72+
6973
bool ReactNativeFeatureFlags::enableDoubleMeasurementFixAndroid() {
7074
return getAccessor().enableDoubleMeasurementFixAndroid();
7175
}

packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlags.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
* This source code is licensed under the MIT license found in the
55
* LICENSE file in the root directory of this source tree.
66
*
7-
* @generated SignedSource<<80dcd75591a392144c2fd2817cc4408a>>
7+
* @generated SignedSource<<b941543bc6f12dbb0e12ac2ae0042186>>
88
*/
99

1010
/**
@@ -89,6 +89,11 @@ class ReactNativeFeatureFlags {
8989
*/
9090
RN_EXPORT static bool enableCustomFocusSearchOnClippedElementsAndroid();
9191

92+
/**
93+
* Enables destructor calls for ShadowTreeRevision in the background to reduce UI thread work.
94+
*/
95+
RN_EXPORT static bool enableDestroyShadowTreeRevisionAsync();
96+
9297
/**
9398
* When enabled a subset of components will avoid double measurement on Android.
9499
*/

0 commit comments

Comments
 (0)