drainPreallocateViewsQueue blocks the Android UI thread on the JS thread's executeMount since #58890

未关闭
#59,244 0 条评论 0 个 reaction 已指派 0 人 在 GitHub 查看

维护者通常 2 天内回复

还没有人认领这个 Issue。

评估

难度
3/5
预计耗时
1-2 天
新手友好度
55/100
Issue 类型
缺陷
描述清晰度
描述清楚
活跃度
活跃
技术栈
android, cpp, java, react-native

调研方向

Start with FabricMountingManager.cpp around drainPreallocateViewsQueue and executeMount, then read the call site in FabricUIManager.java and the linked reproducer’s README. Reproduce the empty-queue lock wait with the provided Perfetto steps and compare against the pre-#58890 behavior. Done when empty drains no longer wait behind executeMount and the supplied Android scenes show no such waits.

由索引模型根据 Issue 内容生成。

描述

Description

Since #58890, FabricMountingManager::drainPreallocateViewsQueue takes allocatedViewsMutex_ on every call, whether or not anything is queued (FabricMountingManager.cpp). FabricUIManager calls it at the start of every frame callback (FabricUIManager.java), and executeMount holds the same mutex on the JS thread across a transaction's mutations (FabricMountingManager.cpp). So a frame that starts while the JS thread builds a large commit's mount items waits on the UI thread until they are built, with nothing to pre-allocate. Before #58890 the drain took the mutex once per queued view, so an empty queue never waited; 0.88.0 still does that.

Release RNTester from main at 202d93931c, with the reproducer's scenes: 600 or 2400 views mounted and unmounted in turn every 1.5 s beside a native-driven Animated.spring, 2400 at each fling of a horizontal ScrollView, and 2400 over 160 translucent full-window views.

Galaxy S23, Android 14, 120 Hz RedMagic NX809J, Android 16, 120 Hz Mi MIX 3, Android 10, 60 Hz
waits of 1 ms or more in the drain 12 in 50 mounts 2 in 51 mounts 26 in 48 mounts
with nothing queued, while mqt_v_js was in executeMount 12, 1.2–7.9 ms 2, 1.6 and 1.9 ms 24, 1.0–7.0 ms

On the S23 the two longest waits made their frames 9.3 and 8.8 ms long, past the next vsync. The spring and fling scenes built from main at b8ec87e457, before #58890, never waited 1 ms or more in 36 mounts on the S23; at 202d93931c they waited 5 times in 36.

Could the drain return before taking the mutex when nothing is queued, as it did before #58890? A drain with views still queued would wait for executeMount as it did then.

Steps to reproduce
  1. Apply the reproducer's two patches to main at 202d93931c: the scenes in RNTester's View examples, and a trace section around the drain call.
  2. Build RNTester release for arm64-v8a and open View → "Pre-mount burst: 1200 items".
  3. Record a Perfetto trace of 24 s with sched/sched_switch and the app's view and gfx atrace categories.
  4. Find the FabricUIManager::drainPreallocateViewsQueue slices on the main thread that start during FabricMountingManager::executeMount on mqt_v_js: the main thread sleeps in them until about 0.4 ms before executeMount returns, and they contain no FabricMountingManager::preallocateRegisteredView.

Expected: with nothing queued, the drain returns at once, as it did before #58890.
Actual: the main thread waits in the drain for the JS thread's executeMount, 1.2–7.9 ms on the S23 (the table above).

React Native Version

nightly (main at 202d93931c)

Affected Platforms

Runtime - Android

Areas

Fabric - The New Renderer

Output of npx @react-native-community/cli info
System:
  OS: Windows 11 10.0.26200
  CPU: "(32) x64 AMD Ryzen 9 9950X3D 16-Core Processor          "
  Memory: 166.93 GB / 255.67 GB
Binaries:
  Node:
    version: 26.8.1
    path: C:\Program Files\nodejs\node.EXE
  Yarn:
    version: 1.22.22
    path: ~\AppData\Roaming\npm\yarn.CMD
  npm:
    version: 12.0.1
    path: C:\Program Files\nodejs\npm.CMD
  Watchman: Not Found
SDKs:
  Android SDK:
    API Levels:
      - "33"
      - "35"
      - "35"
      - "35"
      - "36"
      - "37"
    Build Tools:
      - 35.0.0
      - 36.0.0
      - 36.1.0
      - 37.0.0
    System Images:
      - android-26 | Google APIs Intel x86_64 Atom
      - android-28 | Google APIs Intel x86_64 Atom
      - android-29 | Google APIs Intel x86_64 Atom
      - android-30 | Google APIs Intel x86_64 Atom
      - android-31 | Google APIs Intel x86_64 Atom
      - android-32 | Google APIs Intel x86_64 Atom
      - android-33 | Google APIs Intel x86_64 Atom
      - android-34 | Google APIs Intel x86_64 Atom
      - android-35 | Google APIs Intel x86_64 Atom
      - android-36.1 | Google Play Intel x86_64 Atom
      - android-36.1 | Pre-Release 16 KB Page Size Google Play Intel x86_64 Atom
      - android-37.0 | Google APIs Intel x86_64 Atom
    Android NDK: Not Found
  Windows SDK: Not Found
IDEs:
  Android Studio: AI-252.27397.103.2522.14617522
  Visual Studio: Not Found
Languages:
  Java:
    version: 17.0.20.1
    path: /c/Program Files/Microsoft/jdk-17.0.20.101-hotspot/bin/javac
  Ruby: Not Found
npmPackages:
  "@react-native-community/cli": Not Found
  react: Not Found
  react-native: Not Found
  react-native-windows: Not Found
npmGlobalPackages:
  "*react-native*": Not Found
Android:
  hermesEnabled: false
  newArchEnabled: false
iOS:
  hermesEnabled: Not found
  newArchEnabled: Not found

Run in the React Native checkout I built RNTester from; the builds are main at 202d93931c and b8ec87e457.

Stacktrace or Logs
No crash. Galaxy S23, Android 14, 120 Hz; release RNTester from main at 202d93931c,
View → "Pre-mount burst: 1200 items", one commit:

mqt_v_js  FabricMountingManager::executeMount            7.64 ms
main      Choreographer#doFrame                           8.83 ms, frames 8.34 ms apart
            FabricUIManager::drainPreallocateViewsQueue   7.19 ms, asleep for 7.16 ms of it,
                                                          no preallocateRegisteredView in it
main asleep from 0.09 ms after executeMount began until 0.40 ms before it returned
MANDATORY Reproducer

https://github.com/YevheniiKotyrlo/react-native-evidence/tree/main/preallocation-drain-lock-wait

Screenshots and Videos

The scenes, the builds, how they were traced and every wait are on this page.

主要语言
C++
星标
127k
派生
25.4k
平均合并
2 天 9 小时
30 天内合并 PR
91

环境准备

从这里开始

  1. 先读完整个 Issue,再读项目的贡献指南。
  2. 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
  3. Fork 仓库,在一个分支上完成修改。
  4. 提交 Pull Request,并在描述里引用这个 Issue 编号。

react/react-native 的其他 Issue

查看 react/react-native 的全部 Issue

相似的 Issue

更多 C++ Issue

把新 issue 发到你的邮箱

精选适合新手参与的 GitHub issue 摘要。