Skip to content

Commit 2160b50

Browse files
rozelefacebook-github-bot
authored andcommitted
Delete ShadowTreeRevision on background thread (#50997)
Summary: 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 will be introduced in future diffs for each platform. 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] Differential Revision: D73688009
1 parent ae2773f commit 2160b50

23 files changed

+253
-54
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<<1172f5f2fda3a7d7835f619376f65b3a>>
7+
* @generated SignedSource<<810c19122e7fa126be4f614e15ce1fe3>>
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<<b045498e0c54e6c12cdf6a6dc25fd109>>
7+
* @generated SignedSource<<6e0645921430c674dbf94d3a64411ab9>>
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
@@ -155,6 +156,15 @@ internal class ReactNativeFeatureFlagsCxxAccessor : ReactNativeFeatureFlagsAcces
155156
return cached
156157
}
157158

159+
override fun enableDestroyShadowTreeRevisionAsync(): Boolean {
160+
var cached = enableDestroyShadowTreeRevisionAsyncCache
161+
if (cached == null) {
162+
cached = ReactNativeFeatureFlagsCxxInterop.enableDestroyShadowTreeRevisionAsync()
163+
enableDestroyShadowTreeRevisionAsyncCache = cached
164+
}
165+
return cached
166+
}
167+
158168
override fun enableDoubleMeasurementFixAndroid(): Boolean {
159169
var cached = enableDoubleMeasurementFixAndroidCache
160170
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<<007721988dfdf572f8ac218744341e60>>
7+
* @generated SignedSource<<5b3d44f1473827909204e2f689f71400>>
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<<6b10c147b3f1753448f599ae4fb43387>>
7+
* @generated SignedSource<<63d07f55459f7e9a5b0952c7b22ef36a>>
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<<b64966fc245f53645726747ec93a15d1>>
7+
* @generated SignedSource<<dabe88124e359650d3a654b66f968547>>
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
@@ -169,6 +170,16 @@ internal class ReactNativeFeatureFlagsLocalAccessor : ReactNativeFeatureFlagsAcc
169170
return cached
170171
}
171172

173+
override fun enableDestroyShadowTreeRevisionAsync(): Boolean {
174+
var cached = enableDestroyShadowTreeRevisionAsyncCache
175+
if (cached == null) {
176+
cached = currentProvider.enableDestroyShadowTreeRevisionAsync()
177+
accessedFeatureFlags.add("enableDestroyShadowTreeRevisionAsync")
178+
enableDestroyShadowTreeRevisionAsyncCache = cached
179+
}
180+
return cached
181+
}
182+
172183
override fun enableDoubleMeasurementFixAndroid(): Boolean {
173184
var cached = enableDoubleMeasurementFixAndroidCache
174185
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<<1e9beb93c98a0a82d030b7a3ea1cf7e4>>
7+
* @generated SignedSource<<2933f632fa82415806a9ee398881bd56>>
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<<ac6b60d9d2062eda500e291fb2167076>>
7+
* @generated SignedSource<<97681c320cbce9bacd0104828ece6020>>
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");
@@ -357,6 +363,11 @@ bool JReactNativeFeatureFlagsCxxInterop::enableCustomFocusSearchOnClippedElement
357363
return ReactNativeFeatureFlags::enableCustomFocusSearchOnClippedElementsAndroid();
358364
}
359365

366+
bool JReactNativeFeatureFlagsCxxInterop::enableDestroyShadowTreeRevisionAsync(
367+
facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop> /*unused*/) {
368+
return ReactNativeFeatureFlags::enableDestroyShadowTreeRevisionAsync();
369+
}
370+
360371
bool JReactNativeFeatureFlagsCxxInterop::enableDoubleMeasurementFixAndroid(
361372
facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop> /*unused*/) {
362373
return ReactNativeFeatureFlags::enableDoubleMeasurementFixAndroid();
@@ -588,6 +599,9 @@ void JReactNativeFeatureFlagsCxxInterop::registerNatives() {
588599
makeNativeMethod(
589600
"enableCustomFocusSearchOnClippedElementsAndroid",
590601
JReactNativeFeatureFlagsCxxInterop::enableCustomFocusSearchOnClippedElementsAndroid),
602+
makeNativeMethod(
603+
"enableDestroyShadowTreeRevisionAsync",
604+
JReactNativeFeatureFlagsCxxInterop::enableDestroyShadowTreeRevisionAsync),
591605
makeNativeMethod(
592606
"enableDoubleMeasurementFixAndroid",
593607
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<<e1f86665fe4df2f2ee9fb82261760a69>>
7+
* @generated SignedSource<<72e20c89d2f0b43560e08ee50eca8826>>
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<<17feaf7e1ce72109e0f99902ac8ad1e2>>
7+
* @generated SignedSource<<503f868f462746db7b8631cab0f4d545>>
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<<28265b23648f7634587376b9f0320f7b>>
7+
* @generated SignedSource<<6e6f93037f91d4717b15d722afc160e0>>
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)