Skip to content

Commit 33f9944

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 0c58ccf commit 33f9944

28 files changed

+350
-58
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<<62ec58d76b9e14b3e1e4e10e62fc196a>>
7+
* @generated SignedSource<<a31885acf3f5f3b02253ee810e7e2bcd>>
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<<03596dcddbe8976adfcf454b9b35e3c3>>
7+
* @generated SignedSource<<a3266a2ff824d99240b8d0652cba2d26>>
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<<eeeeed4a48a3627d5d51635da9c15cb7>>
7+
* @generated SignedSource<<e864a58b57069c96819b94081e466893>>
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<<7d343ae73a15daf1a4d8d85ba959dd81>>
7+
* @generated SignedSource<<9477b557c75477041d05d8a842f4c97a>>
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<<f4ae0172bfb1c4d64213c0cd14320bdd>>
7+
* @generated SignedSource<<bb808a422c37e8766ec620f15550b72f>>
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<<3b830939241e6fde03e6e63faa7232ff>>
7+
* @generated SignedSource<<61e0ae1026e903d9934abc118149a56f>>
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<<a176560c48267f25dd8fdb5a1a232d37>>
7+
* @generated SignedSource<<4bf2735cbae23f4c465fe703c6229326>>
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<<dae3956726e1cbbb2b78d9fffaeca6dd>>
7+
* @generated SignedSource<<234bfb4702e420ea5ea51757eb7a92da>>
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<<42e3fd2958733abb652f73d87b5b4a7d>>
7+
* @generated SignedSource<<b1e7b65c583107641b52335a22be94d4>>
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<<871f96445659d2f927efeda5480b6f96>>
7+
* @generated SignedSource<<9989109db32cd6d944ac77da6843f8e4>>
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)