Skip to content

Commit 35e0782

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 58a9046 commit 35e0782

28 files changed

+361
-67
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<<991cfdadfc26e470da425a986d75c766>>
7+
* @generated SignedSource<<416e60f0ed13027fcd2586b15916d98a>>
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<<65268cf15face782370694a2a5bd8c3f>>
7+
* @generated SignedSource<<c9c74b0ad68b3b4d50471c3299c13ba9>>
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
@@ -157,6 +158,15 @@ internal class ReactNativeFeatureFlagsCxxAccessor : ReactNativeFeatureFlagsAcces
157158
return cached
158159
}
159160

161+
override fun enableDestroyShadowTreeRevisionAsync(): Boolean {
162+
var cached = enableDestroyShadowTreeRevisionAsyncCache
163+
if (cached == null) {
164+
cached = ReactNativeFeatureFlagsCxxInterop.enableDestroyShadowTreeRevisionAsync()
165+
enableDestroyShadowTreeRevisionAsyncCache = cached
166+
}
167+
return cached
168+
}
169+
160170
override fun enableDoubleMeasurementFixAndroid(): Boolean {
161171
var cached = enableDoubleMeasurementFixAndroidCache
162172
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<<6650ca57c9b43c16506ea8a95cf95b8a>>
7+
* @generated SignedSource<<f8fbadb52c5645f54e14d6f2cd1490c5>>
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<<906ab78c1c4099bc4711c102885becd0>>
7+
* @generated SignedSource<<a56643b81ee5e53a4f13f11c865bd929>>
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<<aa86a9c0807638f1f44ced69462b1d17>>
7+
* @generated SignedSource<<8da35e9ec869f321b417b41a81b95513>>
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
@@ -171,6 +172,16 @@ internal class ReactNativeFeatureFlagsLocalAccessor : ReactNativeFeatureFlagsAcc
171172
return cached
172173
}
173174

175+
override fun enableDestroyShadowTreeRevisionAsync(): Boolean {
176+
var cached = enableDestroyShadowTreeRevisionAsyncCache
177+
if (cached == null) {
178+
cached = currentProvider.enableDestroyShadowTreeRevisionAsync()
179+
accessedFeatureFlags.add("enableDestroyShadowTreeRevisionAsync")
180+
enableDestroyShadowTreeRevisionAsyncCache = cached
181+
}
182+
return cached
183+
}
184+
174185
override fun enableDoubleMeasurementFixAndroid(): Boolean {
175186
var cached = enableDoubleMeasurementFixAndroidCache
176187
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<<bad6f4d9b4c7ba419c2ad37a5089c3e7>>
7+
* @generated SignedSource<<2b5bef41a6f2000751f2e94976196e87>>
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<<65232e117b548982fd5c59502599b1bb>>
7+
* @generated SignedSource<<1ac26b645f1e71a31acef8f827e87b52>>
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");
@@ -369,6 +375,11 @@ bool JReactNativeFeatureFlagsCxxInterop::enableCustomFocusSearchOnClippedElement
369375
return ReactNativeFeatureFlags::enableCustomFocusSearchOnClippedElementsAndroid();
370376
}
371377

378+
bool JReactNativeFeatureFlagsCxxInterop::enableDestroyShadowTreeRevisionAsync(
379+
facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop> /*unused*/) {
380+
return ReactNativeFeatureFlags::enableDestroyShadowTreeRevisionAsync();
381+
}
382+
372383
bool JReactNativeFeatureFlagsCxxInterop::enableDoubleMeasurementFixAndroid(
373384
facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop> /*unused*/) {
374385
return ReactNativeFeatureFlags::enableDoubleMeasurementFixAndroid();
@@ -610,6 +621,9 @@ void JReactNativeFeatureFlagsCxxInterop::registerNatives() {
610621
makeNativeMethod(
611622
"enableCustomFocusSearchOnClippedElementsAndroid",
612623
JReactNativeFeatureFlagsCxxInterop::enableCustomFocusSearchOnClippedElementsAndroid),
624+
makeNativeMethod(
625+
"enableDestroyShadowTreeRevisionAsync",
626+
JReactNativeFeatureFlagsCxxInterop::enableDestroyShadowTreeRevisionAsync),
613627
makeNativeMethod(
614628
"enableDoubleMeasurementFixAndroid",
615629
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<<980b6545944b8053fbe9901d3e4746ee>>
7+
* @generated SignedSource<<38d2d525708cbd8ac5d19004df2700c3>>
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<<7929b1ed09571f4afd84196d8c672615>>
7+
* @generated SignedSource<<be20e25a66baf1bf5004875adac8496c>>
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<<0588d6b7fda4af37b3ba8ec5ad88657b>>
7+
* @generated SignedSource<<4f2e74a54a95d58283bdf369b616106e>>
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)