From 01c9155b856a63b69abb6ada2a08d1c61e4d3c01 Mon Sep 17 00:00:00 2001 From: Zeya Peng Date: Wed, 22 Apr 2026 07:22:24 -0700 Subject: [PATCH] Fix debug build memory leak from fabric marker in updatePropsSynchronously (#56561) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: ## Changelog: [Internal] [Fixed] - Fix debug build memory leak from fabric marker in updatePropsSynchronously ## Problem `FabricUIManager.synchronouslyUpdateViewOnUIThread` logs `FABRIC_UPDATE_UI_MAIN_THREAD_START/END` fabric markers with a unique, ever-incrementing `commitNumber`. While `Fb4aReactFabricPerfLogger` consumed these markers correctly (via its `EventMetadata` pattern), `DevToolsReactPerfLogger` stored them in its `fabricCommitMarkers` map and only cleaned up entries on `FABRIC_BATCH_EXECUTION_END` — which is never emitted for synchronous updates. At 60fps with multiple animated views, ~300 orphaned `FabricCommitPoint` entries accumulated per second, causing unbounded memory growth. ## Why only UPDATE_UI_MAIN_THREAD is affected All other fabric markers (COMMIT, DIFF, LAYOUT, FINISH_TRANSACTION, BATCH_EXECUTION) are emitted from the normal commit lifecycle in C++ → `IntBufferBatchMountItem`. They share the same `commitNumber` and always terminate with `BATCH_EXECUTION_END`, so they get cleaned up. `UPDATE_UI_MAIN_THREAD` is the only marker emitted from a separate path (`synchronouslyUpdateViewOnUIThread`) with its own `commitNumber` space (starting at 10000) and no `BATCH_EXECUTION_END`. ## Fix `DevToolsReactPerfLogger` now also treats `FABRIC_UPDATE_UI_MAIN_THREAD_END` as a commit-end signal, triggering `onFabricCommitEnd` and cleanup of the `fabricCommitMarkers` entry. This is safe because `UPDATE_UI_MAIN_THREAD` markers are only emitted by `synchronouslyUpdateViewOnUIThread` (which never emits `BATCH_EXECUTION_END`), while normal commits use `BATCH_EXECUTION_END` (and never emit `UPDATE_UI_MAIN_THREAD`). No double-cleanup risk. Reviewed By: cipolleschi Differential Revision: D101843147 --- .../com/facebook/react/fabric/DevToolsReactPerfLogger.kt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/DevToolsReactPerfLogger.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/DevToolsReactPerfLogger.kt index e845718dce5..ff635f2b934 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/DevToolsReactPerfLogger.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/DevToolsReactPerfLogger.kt @@ -134,7 +134,10 @@ public class DevToolsReactPerfLogger : FabricMarkerListener { } commitPoint.addPoint(name, FabricCommitPointData(timestamp, counter)) - if (name == ReactMarkerConstants.FABRIC_BATCH_EXECUTION_END && timestamp > 0) { + if ( + (name == ReactMarkerConstants.FABRIC_BATCH_EXECUTION_END || + name == ReactMarkerConstants.FABRIC_UPDATE_UI_MAIN_THREAD_END) && timestamp > 0 + ) { onFabricCommitEnd(commitPoint) fabricCommitMarkers.remove(instanceKey) }