logo
积分中心
RN 性能调优之基础定界与 trace 分析介绍
头像 鸿蒙小助手 2026-10-21 14:51:08    发布
17 浏览 1 点赞 2 收藏

本原创文章帖发布在华为开发者联盟社区,欢迎开发者前往访问评论交流,更多与该内容相关讨论,请点击原帖查看:

RN 性能调优之基础定界与 trace 分析介绍-华为开发者话题 | 华为开发者联盟


本文是 RN 性能定界定位的基础篇,面向 RNOH 应用开发者,介绍三方面内容:

  1. RNOH 的线程模型,以及一次页面更新经过的环节;

  2. trace 的采集与查看方法;

  3. RNOH 在 trace 中输出的关键标记及其含义。

      完成基础篇阅读后,如需深入定位具体问题,请继续阅读:

         • RN 性能调优之滑动卡顿问题介绍

         • RN 性能调优之点击响应和完成时延分析介绍


名词说明

      本文会反复用到以下名词,含义见下表,阅读过程中可随时查阅:


名词解释
RNInstance一个 RN 运行实例(含 JS 运行时和渲染环境),一个应用可以同时存在多个
Surface由 RN 渲染的独立显示区域,通常对应一个页面、弹层或卡片
FabricReact Native 新架构的渲染系统,负责影子树的创建、布局、对比和挂载
影子树(ShadowTree)组件树在ArkUI侧的中间表示,布局与对比先在影子树上完成,差异再应用到真实界面
mutations新旧影子树对比后生成的变更指令列表(详见 §1.2)
TurboModuleJS 调用ArkUI能力的模块(网络、文件、传感器等)
ArkUI鸿蒙UI 框架,RN 的组件最终由它创建和绘制
Render Service系统合成服务,负责将各应用的画面合成到屏幕上
App Frame / RS Frame性能工具中的两条帧泳道:应用产帧 / 系统合成帧
trace性能分析记录,按时间轴展示各线程在各时间段的执行内容

1. RNOH 线程模型与渲染链路

1.1 四线程模型

      RNOH 内部有四类线程,各自承担不同职责:


线程职责QoS 优先级trace 中如何识别
MAIN/UI应用主线程(也是 UI 线程),每个应用进程只有一个。负责 ArkUI 组件生命周期管理(CREATE/UPDATE/INSERT/REMOVE/DELETE)、组件树管理、TurboModule 业务执行、交互事件处理跟随系统主线程主线程名不会被改成 RNOH_MAIN(复用主线程),需通过"应用主线程 + RNOH 调用栈"确认
JSJS 运行时线程,通过 Hermes 执行 React 代码。负责 bundle 加载、ShadowTree 创建、Yoga 布局计算、新老树 diff 生成 mutations、交互事件处理。每个 RNInstance 绑定一个独立 JS 线程QOS_USER_INTERACTIVE(用户交互级,与 UI 渲染同档的高优先级)搜索线程名 RNOH_JS
BACKGROUND实验特性,开启后会将 JS 线程的部分布局、ShadowTree 比较任务迁移到该线程,降低 JS 线程负荷。由于涉及复杂线程通信,稳定性有风险,正式商用版本不要开启未单独设置开启后搜索线程名 RNOH_BACKGROUND;默认不创建该线程
WORKERTurboModule 工作线程,将 TurboModule 运行在独立线程,避免与主线程 UI 绘制竞争资源。需要在继承 RNAbility 后重写 getRNOHWorkerScriptUrl 方法配置跟随 Worker 线程默认搜索 WorkerThread

      线程之间的通信方向:JS → Main 通过任务投递进入主线程事件循环;Main → JS 通过消息队列投递到 JS 线程。

      下图是一次典型操作中各线程的 trace 示例(线程号 53130 为 MAIN 线程,53214/53216 为两个 JS 线程实例):

1.2 渲染三阶段

      RNOH 的渲染流程继承自 React Native 新架构,分为三个阶段,分布在不同线程执行:

         • 渲染(Render):在 JS 线程中,React 执行业务代码创建 React 元素树(React Element Tree),然后通过 JSI 在 C++ 中创建 React 影子树(React Shadow Tree)。

         • 提交(Commit):影子树创建完成后,通过 Yoga 引擎进行布局计算,然后与上一次的影子树对比,生成变更指令列表(mutations)。

         • 挂载(Mount):mutations 被提交到主线程,转化为 ArkUI 组件树操作(CREATE/INSERT/UPDATE/REMOVE/DELETE),最终由 ArkUI 完成绘制和合成。

      下图以一次点击跳转到 1500 个 Text 组件页面为例,展示 trace 中的渲染三阶段实例:

      关于 mutations:mutations 是 Fabric 对新旧影子树做 diff 后生成的变更指令列表,每条指令描述一个组件操作(如创建 tag=42 的 Text 组件、更新 tag=10 的 View 属性、将 tag=5 插入到 tag=3 下)。主线程逐条执行这些指令来完成界面更新。

1.3 性能链路

      一次 RN 页面更新通常跨越以下环节。图中标注了 ①~⑥ 序号,与 §1.2"渲染三阶段 trace 实例"图(点击跳转到 1500 个 Text 组件页面)中的标注一一对应:

      各环节与图中序号、渲染三阶段、trace 标记的对应关系(trace 标记的含义见 §3):


执行环节图中序号渲染三阶段所在线程对应 trace 标记
手指点击、输入分发到 RN Surface①输入RNOH_MAIN#RNOH::ArkUISurface::onTouchEvent::DOWN/UP
JS 线程响应事件、执行 React 业务代码②渲染(Render)RNOH_JS#RNOH::MessageQueueThread::runOnQueue
通过 JSI 创建影子树③渲染(Render)RNOH_JSReactMarker::FABRIC_COMMIT、cloneNode 等节点树操作
Yoga 布局计算④提交(Commit)RNOH_JSReactMarker::FABRIC_LAYOUT、#RNOH::TextMeasurer::measure
新旧影子树对比,生成 mutations⑤提交(Commit)RNOH_JSReactMarker::FABRIC_DIFF
mutations 送主线程启动渲染⑥提交(Commit)收尾RNOH_JS → RNOH_MAINReactMarker::FABRIC_FINISH_TRANSACTION(主线程开始处理事务)
mutations 挂载(CREATE/INSERT/UPDATE/REMOVE/DELETE)-挂载(Mount)RNOH_MAINReactMarker::FABRIC_BATCH_EXECUTION、#RNOH::MountingManager::doMount
ArkUI 布局/绘制、Render Service 合成上屏-挂载(Mount)之后RNOH_MAIN / Render ServiceFlushVsync 等系统 trace

      图中 ①~⑥ 的逐步说明也可参考渲染三阶段。

      RNOH_MAIN 就是应用主线程,RNOH 在其事件循环上注册回调,不创建新线程。在 trace 中通常需要通过应用主线程身份和 RNOH 调用栈确认,不能只按线程名匹配。RNOH_JS 是独立线程,但线程名也只是一条线索,最终仍需用调用栈和时间关系确认。

1.4 指标定义

      在分析 trace 前,需要统一以下指标的定义和测量方法。

卡顿和丢帧

      帧预算由问题窗口内的实际目标刷新率决定:


单帧预算(ms) = 1000 / 目标刷新率(Hz)

      例如,60 Hz、90 Hz、120 Hz 对应的理论预算约为 16.7 ms、11.1 ms、8.3 ms。设备可能动态切换刷新率,因此不能固定使用 16.7 ms,也不能仅用"FPS 低于 60"判断丢帧。应在 DevEco Profiler 中读取 Display、H:PreferredFrameRate 或等价信息,并结合 App Frame、RS Frame 判断。

响应时延

      响应时延描述输入事件到首个可见反馈之间的时间,其数值与起止点的选取直接相关:

         • 起点:系统工具通常取点击事件上报时刻,而不是物理触屏时刻;

         • 终点:通常取首个响应帧上屏。

      因此报告中必须记录所用工具和起止点定义。不同工具、不同版本对起止点的取法可能不同,不能把 RNOH 内部的触摸 trace 直接当作端到端响应时延。

完成时延

      完成时延描述操作开始到目标页面达到工具所定义"完成状态"的时间。不同测试工具可能以页面切换后的目标帧、动画结束或占位内容加载完成作为终点。业务还可能把"关键内容可见"定义为完成。测试基线、问题复现和优化前后对比必须使用同一终点。

      RNOH 的 CONTENT_APPEARED 表示根节点挂载到 ArkUI 内容容器(NodeContent);ROOT_VIEW_TTI 计算为从 APP_STARTUP_START 到 CONTENT_APPEARED 的耗时。它们是 RNOH 内部阶段标记,不证明像素已经上屏、页面内容完整,也不证明页面已经可交互。

   HarmonyOS 指标和工具限制请以性能分析与

2. trace 采集与查看

2.1 RNOH 两类 trace 点

      RNOH 在 trace 中留下的标记分为两类,粒度和用途完全不同:


维度RNOHMarker(阶段级)TraceSection(函数级)
trace 中搜索ReactMarker::#RNOH::
粒度标记一个完整阶段的起止(如 Bundle 加载开始→结束)标记单个函数或代码块的执行区间
典型时间跨度大(数十毫秒到数秒)小(微秒到毫秒级)
是否跨线程可以(起点和终点可以在不同线程)不可以(限同一线程内)
编译开关WITH_HITRACE_REACT_MARKERWITH_HITRACE_SYSTRACE

      两类标记的用途可以这样区分:分析"某个阶段花了多久"(如 Bundle 加载、启动)时查看 RNOHMarker,分析"哪个函数耗时"(如挂载、触摸分发)时查看 TraceSection。两类标记的具体含义见 §3。

2.2 开启 trace 编译开关

      两个编译宏默认关闭,需要手动开启:


编译宏控制的 trace 类型默认值
WITH_HITRACE_REACT_MARKERReactMarker::* 异步 trace(阶段标记)OFF
WITH_HITRACE_SYSTRACE#RNOH::* 同步 trace(函数标记)+ JS 侧 nativeTrace* APIOFF

   注意:开关需要在 CMake 引入 RNOH 目录(add_subdirectory)之前设置,才能对 RNOH 源码生效。

三种开启方式(任选其一,普通应用工程用方式 A 即可):

      方式 A:应用 entry 的 CMakeLists.txt 中设置(应用工程推荐,模板默认已开启)


set(WITH_HITRACE_SYSTRACE ON)
set(WITH_HITRACE_REACT_MARKER ON)

      方式 B:build-profile.json5 的 externalNativeOptions.arguments 中传递(不想改 CMakeLists.txt 时使用,配置随工程走)


"externalNativeOptions": {
  "arguments": [
  "-DWITH_HITRACE_SYSTRACE=ON",
  "-DWITH_HITRACE_REACT_MARKER=ON"
  ]
}

      方式 C:第三方工程 CMakeLists.txt 中用 add_compile_definitions(三方库/HAR 场景)


set(WITH_HITRACE_SYSTRACE 1)
add_compile_definitions(WITH_HITRACE_SYSTRACE)
set(WITH_HITRACE_REACT_MARKER 1)
add_compile_definitions(WITH_HITRACE_REACT_MARKER)

2.3 抓取 trace

      正式采集前,先固定测试条件:

         • 使用 release 构建和 release bundle,关闭 Metro、HMR、Inspector 和高频调试日志。

         • 固定设备型号、HarmonyOS 版本、RNOH 版本、刷新率策略、网络和测试数据。

         • 记录温度、是否充电、电量和电源模式;先预热,再重复相同操作至少 5 次。

         • 性能浮层只用于快速观察,正式测量时关闭浮层、录屏和其他可能改变负载的调试功能。

         • 同时保留基线数据与问题数据,避免只分析单次偶发 trace。

      使用 DevEco Profiler(深度录制)抓取 trace 的详细步骤(操作界面以 DevEco Studio 实际版本为准):

      第 1 步:创建分析会话

         1. 使用 release 或 debugOptimized 构建模式安装应用,并连接设备;

         2. 打开 DevEco Studio → Profiler,在设备列表中选择设备,在进程列表中选择要调测的应用(可以是正在运行的应用,也可以是已安装但未启动的应用);

         3. 在新建任务区域选择场景模板,单击 Create Session。常用模板与适用问题:


模板适用问题
Frame卡顿丢帧:采集 App Frame、RS Frame 和渲染相关数据,适合滑动卡顿类问题
Time函数执行效率:深度录制函数调用栈和每帧耗时,展现 ArkTS 到 Native 的跨语言调用栈,适合启动、时延类问题
Launch启动耗时:分析启动周期各阶段耗时和核心线程运行情况

      第 2 步:配置录制选项和泳道

         • 录制详情区域的工具栏上有多个配置图标,鼠标悬停可查看功能提示,按需添加录制选项;

         • 各泳道区域有下拉选项,可调整该泳道的录制功能;录制前可指定要录制的泳道。

      对 RNOH 应用,建议泳道至少包含:**App Frame、RS Frame、应用主线程、RNOH_JS、Render Service**。

      第 3 步:启动录制并复现问题

      单击任务窗口左上角(或左侧任务列表)的启动按钮,等待任务状态由 "initializing" 变为 "recording" 后,在设备上操作应用、复现性能问题。录制过程中不能再操作其他模板;如需更换模板,需结束本次录制后重新创建会话。

      第 4 步:停止录制并等待解析

      复现完成后单击停止按钮,泳道任务状态由 "analyzing" 变为 "rendering" 时解析结束,右侧详情区域显示分析结果;数据量较大时解析需要时间,请耐心等待。若 ArkTS Callstack、Callstack 等泳道显示 No Data,可将光标悬浮在泳道名称处的三角告警图标上查看原因。

      第 5 步:保存 trace 文件

      保存 .htrace 文件,便于后续查询和复核。

      抓取完成后,即可在泳道中查看应用主线程、RNOH_JS 等线程的活动区间(同 §1.1 的示例):

      更详细的 trace 抓取操作(包括命令行方式、采样配置、trace 文件解析等)请参考 HarmonyOS 官方文档Deep Recording 使用指导,其支持的全部场景模板(Snapshot、Allocation、ArkUI、Energy、ArkWeb、Network、Concurrency、GPU、CPU 等)也以该文档为准。

      采集清单:每个问题建议至少提供 — 复现步骤和问题时间点、应用包类型和版本信息、DevEco Profiler trace 文件、App Frame/RS Frame/主线程/RNOH_JS 泳道数据、操作录屏或截图、基线版本与问题版本对照数据。

2.4 查看 trace 的技巧

      • 定位 JS 线程:在 trace 中搜索线程名RNOH_JS。

      • 定位阶段标记:搜索ReactMarker::,可快速定位到启动、Bundle 加载、Fabric 提交等阶段的起止。

      • 定位函数执行:搜索#RNOH::,可定位到具体的函数调用区间(如挂载、触摸分发、TurboModule 调用)。

      • 定位异常窗口:先看 App Frame 和 RS Frame 泳道中的红色异常帧,然后缩放到该时间区间,查看该窗口内各线程的活动。

      • 确认线程身份:RNOH_MAIN 不在 trace 中直接显示此名称(主线程复用应用自身线程名),需通过应用主线程 + #RNOH::TaskExecutor::runTask等 TraceSection 调用栈确认。

3. RNOH 关键 trace 点解读

3.1 ReactMarker(阶段级异步 trace)

      React Marker 的作用是监听 RN 应用生命周期中的关键事件并打点,方便开发者分析性能问题。打点覆盖了从启动到渲染的完整时间线,可归纳为四类:

         • 启动初始化:运行时/实例/上下文创建、ArkUI模块注册;

         • Bundle 加载:下载、格式转换、分段注册、执行;

         • 页面内容显示:内容出现、Surface 前后台切换;

         • Fabric 渲染:提交、布局、diff、挂载。

      该类 trace 需要开启 WITH_HITRACE_REACT_MARKER 编译开关(见 §2.2)。

      查看 ReactMarker 的 trace 时,需要注意标记名与 trace 显示名之间的映射关系:

         • 标记大多成对出现,带_START/_STOP(或_END)后缀,例如RUN_JS_BUNDLE_START和RUN_JS_BUNDLE_STOP;

         • 成对的两个标记在 trace 中显示为同一个名称,如ReactMarker::RUN_JS_BUNDLE(部分工具显示为H:ReactMarker::RUN_JS_BUNDLE::Tag::<tag>),_START/_STOP后缀不体现在名称中,而是分别对应该异步 trace 时间条的开始和结束;

         • 带 tag 的标记会在名称后追加::Tag::<tag>;

         • 个别标记名与 trace 显示名不同,如JS_BUNDLE_STRING_CONVERT_START/STOP在 trace 中显示为ReactMarker::loadApplicationScript_StringConvert。

      以下是在 trace 工具中查看 ReactMarker 的示例:

      图中红色框 1 代表的是应用进程,红色框 2 代表的是应用运行过程中打印出来的 React Marker 信息。

以下按阶段分组列出性能定界中最常用的 ReactMarker。在 trace 工具中搜索 ReactMarker:: 即可找到这些标记。

启动与运行时初始化


RNOHMarkerIdtrace 显示名含义可衡量不可衡量
APP_STARTUP_START / APP_STARTUP_STOPReactMarker::APP_STARTUPRNOH 应用启动总阶段启动阶段的总耗时范围各子阶段细节需看其他 marker
INIT_REACT_RUNTIME_START / INIT_REACT_RUNTIME_STOPReactMarker::INIT_REACT_RUNTIMEReact 运行时初始化运行时创建的起止时间JS 引擎是否完全就绪
REACT_INSTANCE_INIT_START / REACT_INSTANCE_INIT_STOPReactMarker::REACT_INSTANCE_INITRNInstance 实例创建实例创建的起止时间实例创建后是否可立即渲染
CREATE_REACT_CONTEXT_START / CREATE_REACT_CONTEXT_STOPReactMarker::CREATE_REACT_CONTEXTReact 上下文创建上下文创建耗时Bundle 是否已加载

Bundle 加载


RNOHMarkerIdtrace 显示名含义可衡量不可衡量
RUN_JS_BUNDLE_START / RUN_JS_BUNDLE_STOPReactMarker::RUN_JS_BUNDLEJS Bundle 执行阶段Bundle 从开始执行到执行完成的时间Bundle 下载时间、业务页面首帧时间
JS_BUNDLE_STRING_CONVERT_START / JS_BUNDLE_STRING_CONVERT_STOPReactMarker::loadApplicationScript_StringConvertBundle 字符串转换Bundle 数据格式转换耗时Bundle 解析和执行时间
REGISTER_JS_SEGMENT_START / REGISTER_JS_SEGMENT_STOPReactMarker::REGISTER_JS_SEGMENTJS 分段注册多 Bundle 分段注册的耗时分段注册后业务是否就绪
DOWNLOAD_START / DOWNLOAD_ENDReactMarker::DOWNLOADJS Bundle 下载阶段Bundle 下载起止时间下载后的缓存命中情况
REACT_BRIDGE_LOADING_START / REACT_BRIDGE_LOADING_ENDReactMarker::REACT_BRIDGE_LOADINGReact 桥接模块加载阶段整体加载阶段耗时加载内部各步骤的细节

Native 模块


RNOHMarkerIdtrace 显示名含义可衡量不可衡量
NATIVE_MODULE_SETUP_START / NATIVE_MODULE_SETUP_STOPReactMarker::NATIVE_MODULE_SETUPArkUI模块注册和初始化所有ArkUI模块注册的总耗时单个模块的初始化时间
INITIALIZE_MODULE_START / INITIALIZE_MODULE_ENDReactMarker::INITIALIZE_MODULE单个模块初始化每个模块的初始化耗时模块初始化后的首次调用时间
PROCESS_PACKAGES_START / PROCESS_PACKAGES_STOPReactMarker::PROCESS_PACKAGES处理所有 PackagePackage 处理的起止时间每个 Package 内部的模块详情
CREATE_UI_MANAGER_MODULE_START / CREATE_UI_MANAGER_MODULE_ENDReactMarker::CREATE_UI_MANAGER_MODULE创建 UI_Manager 模块UIManager 模块创建的起止时间模块创建后的渲染表现
CREATE_MODULE_START / CREATE_MODULE_ENDReactMarker::CREATE_MODULE创建单个 React 模块单个模块创建的耗时模块创建后的调用情况
PROCESS_CORE_REACT_PACKAGE_START / PROCESS_CORE_REACT_PACKAGE_ENDReactMarker::PROCESS_CORE_REACT_PACKAGEReact Native 核心包加载核心包处理的起止时间核心包内部各模块的细节

Surface 生命周期


RNOHMarkerIdtrace 显示名含义可衡量不可衡量
CONTENT_APPEAREDReactMarker::CONTENT_APPEARED应用程序中的内容已成功渲染并显示给用户(根节点挂载到 ArkUI 内容容器 NodeContent)根节点已挂载的时间点像素已上屏、关键内容可见或可交互
ON_HOST_RESUME_START / ON_HOST_RESUME_ENDReactMarker::ON_HOST_RESUMESurface 恢复(可见)Surface 进入可见状态的时间Surface 首帧已渲染完成
ON_HOST_PAUSE_START / ON_HOST_PAUSE_ENDReactMarker::ON_HOST_PAUSESurface 暂停(不可见)Surface 进入不可见状态的时间Surface 资源已释放

Fabric(UI 渲染)


RNOHMarkerIdtrace 显示名含义可衡量不可衡量
FABRIC_COMMIT_START / FABRIC_COMMIT_ENDReactMarker::FABRIC_COMMITFabric 渲染引擎的提交React 一次提交的起止时间提交后是否立即触发挂载
FABRIC_DIFF_START / FABRIC_DIFF_ENDReactMarker::FABRIC_DIFF新旧影子树对比(diff)diff 计算的耗时diff 结果的 mutation 数量
FABRIC_LAYOUT_START / FABRIC_LAYOUT_ENDReactMarker::FABRIC_LAYOUT布局计算(Yoga)布局计算的耗时文本测量的内部细节
FABRIC_FINISH_TRANSACTION_START / FABRIC_FINISH_TRANSACTION_ENDReactMarker::FABRIC_FINISH_TRANSACTIONFabric 事务完成整个事务从提交到完成的耗时挂载是否已在主线程执行完毕
FABRIC_BATCH_EXECUTION_START / FABRIC_BATCH_EXECUTION_ENDReactMarker::FABRIC_BATCH_EXECUTIONmutations 批量挂载执行一批 mutations 在主线程执行的耗时页面内容已完整渲染
FABRIC_UPDATE_UI_MAIN_THREAD_START / FABRIC_UPDATE_UI_MAIN_THREAD_ENDReactMarker::FABRIC_UPDATE_UI_MAIN_THREAD主线程同步更新组件属性在主线程上同步更新单个组件属性的执行区间(避免跨线程延迟)所有 Fabric transaction 的主线程挂载总时长

其他


RNOHMarkerIdtrace 显示名含义可衡量不可衡量
CHANGE_THREAD_PRIORITYReactMarker::CHANGE_THREAD_PRIORITY线程 QoS 优先级变更线程优先级调整的时间点和目标值优先级变更后的实际调度效果

      提示:以上仅列出常用标记。完整的 56 个 ReactMarker 标记定义见源码 RNOH/Performance/RNOHMarker.h;其中部分标记(如 INIT_JS_RUNTIME、TURBO_MODULE_SETUP)不会输出到 trace,仅供 Marker 监听器(日志、性能指标等)使用。React Marker 的 trace 打点操作步骤,以及通过自定义 TurboModule 监听 React Marker 事件的实现方式,参见性能调优的 React Marker 介绍。

3.2 TraceSection(函数级同步 trace)

      以下列出性能定界中最常用的 TraceSection 标记,在 trace 工具中搜索 #RNOH:: 即可找到。这些标记在 trace 中显示为连续的区间切片,可以直接看到函数的执行时长。

触摸与事件


trace 字符串含义所属线程
#RNOH::ArkUISurface::onTouchEvent::DOWN触摸按下事件进入 RN SurfaceRNOH_MAIN
#RNOH::ArkUISurface::onTouchEvent::UP触摸抬起事件进入 RN SurfaceRNOH_MAIN
#RNOH::ArkUISurface::onTouchEvent::MOVE触摸移动事件进入 RN SurfaceRNOH_MAIN
#RNOH::Subject::notifyObservers事件分发给观察者各线程

挂载(Mount)


trace 字符串含义所属线程
#RNOH::MountingManager::doMount开始执行一批 mutations 挂载RNOH_MAIN
#RNOH::MountingManager::didMount <count>挂载完成,count 为 mutation 数量RNOH_MAIN
#RNOH::MountingManager::dispatchCommand分发组件命令(如 scrollTo)RNOH_MAIN

Scheduler(Fabric 调度)


trace 字符串含义所属线程
#RNOH::SchedulerDelegate::performTransaction处理一次 Fabric 事务RNOH_MAIN
#RNOH::SchedulerDelegate::onNextFrame下一帧调度RNOH_MAIN
#RNOH::SchedulerDelegate::didMountScheduler 挂载完成回调RNOH_MAIN
#RNOH::SchedulerDelegate::handleMutation_parallel并行处理 mutationsRNOH_MAIN
#RNOH::SchedulerDelegate::parallelCreateWait并行创建组件等待RNOH_MAIN
#RNOH::SchedulerDelegate::otherCreate串行创建组件RNOH_MAIN

TaskExecutor(任务调度)


trace 字符串含义所属线程
#RNOH::TaskExecutor::runTaskTaskExecutor 执行一个任务各线程
#RNOH::TaskExecutor::runningTask正在执行的任务(含任务 ID)各线程
#RNOH::TaskRunner::task事件循环执行单个任务RNOH_MAIN / RNOH_JS

实例与通信


trace 字符串含义所属线程
#RNOH::RNInstanceCAPI::synchronouslyUpdateViewOnUIThread主线程同步更新组件属性(避免跨线程延迟)RNOH_MAIN
#RNOH::MessageQueueThread::runOnQueue向 JS 队列投递任务RNOH_JS
#RNOH::RNInstanceInternal::callJSFunction调用 JS 函数RNOH_JS
#RNOH::ArkTSTurboModule::call (<name>::<methodName>)ArkTS TurboModule 调用(含模块名和方法名)RNOH_MAIN
#RNOH::TextMeasurer::measure文本测量RNOH_JS

      提示:以上仅列出常用标记。完整的 TraceSection 字符串可通过在源码中搜索 TraceSection s( 或 SystraceSection s( 获取。

3.3 按 trace 时间轴分析一次点击响应

      单个 trace 切片只能说明某个环节的执行区间,定位性能问题时需要按时间顺序将多个切片串联,还原从输入到上屏的完整执行过程。

      以一次点击响应为例,完整的 trace 点序列如下(两条竖线代表两个线程,从上到下即时间顺序):

      依据各切片之间的时间间隔,可以定位耗时集中在哪个环节:

         • 如果onTouchEvent::DOWN到runOnQueue之间很长 → 主线程调度或触摸分发慢;

         • 如果FABRIC_COMMIT到FABRIC_FINISH_TRANSACTION之间很长 → JS 侧 React render/layout/diff 慢;

         • 如果FABRIC_BATCH_EXECUTION到didMount之间很长 → 主线程挂载慢;

         • 如果didMount到首个响应帧上屏之间很长 → ArkUI 布局/绘制或 Render Service 合成慢。

4. 定界方法与常见错误

4.1 责任域划分

      一次有效定界至少给出以下结论之一:


责任域典型证据后续处理方
HarmonyOS 系统或 Render ServiceRS Frame 异常,应用按时提交;同设备多个应用同时劣化系统/图形侧
ArkUI宿主或 ArkTS 业务应用主线程被非 RNOH 的 ArkTS、I/O、图片处理等任务占满ArkUI业务侧
RN JS 业务RNOH_JS 长任务、频繁 React 提交或事件回调过重RN 业务侧
三方 RN 组件异常调用栈集中在三方组件,移除或降级后恢复三方组件维护方
RNOH 框架异常窗口关键路径落在 RNOH 实现,最小示例仍复现,且版本对比显示框架回归RNOH 框架侧
证据不足只有主观现象、平均 FPS 或单个长切片,无法覆盖从输入到上屏的完整过程补充采集

      "使用了 RNOH"不等于"RNOH 框架问题"。例如,大量业务组件一次性提交后,挂载耗时发生在 RNOH 主线程,但如果耗时随业务节点数增长且最小 RNOH 页面正常,通常应先归为 RN 业务负载或组件使用问题,而不是框架缺陷。

4.2 定界前准备

      • 确认 trace 编译开关已开启:检查WITH_HITRACE_REACT_MARKER和WITH_HITRACE_SYSTRACE是否在构建配置中设置为 ON(详见 §2.2)。

      • 测试条件的固定(release 构建、设备/版本/数据固定、预热重复、基线数据与问题数据等)见 §2.3 开头的采集要求,此处不再重复。

4.3 三类问题的快速判定

滑动卡顿丢帧

      详细方法见RN性能调优之滑动卡顿问题介绍。

响应时延

      按"输入锚点 → 首个响应帧上屏"分段测量,定位耗时最长的一段:


输入 → 应用触摸入口 慢 → 系统输入分发 / 主线程调度
触摸分发完成 → JS 事件 晚 → RNOH_JS 排队或阻塞
JS 提交 → 首个变化上屏 晚 → 挂载、ArkUI 或 RS
全程无任何视觉变化 → 先检查业务是否设计了即时反馈

完成时延

      先定义"完成"终点,再分段定位责任方:


数据/网络未就绪 → 业务或服务侧
JS render/commit 晚 → RN JS 业务或三方组件
mutations 已产生但挂载晚 → RNOH_MAIN、节点规模或同步阻塞
应用按时提交但上屏晚 → ArkUI/RS/系统侧
仅 CONTENT_APPEARED 早 → 不能据此判定页面已经完成

      详细方法见RN性能调优之点击响应和完成时延分析介绍。

4.4 常见错误定界

      • 只看 JS FPS/UI FPS 就分责:浮层是采样指标,适合发现趋势,不足以证明一次异常的关键路径。

      • 只看一个超过帧预算的函数:它可能不在异常帧、可能运行在非关键线程,也可能被后续流水线吸收。

      • 应用和 RS 同时红就判系统问题:应用晚提交也会向 RS 传导,必须看最早异常点。

      • RNOH 调用栈长就判框架问题:需要结合输入规模、最小示例和版本对照。

      • **把 CONTENT_APPEARED 当完成时延终点**:该标记早于实际上屏和业务内容完整。

      • 用 debug 数据和 release 基线比较:构建、日志、Inspector 和 bundle 差异会破坏对照条件。

      • 把平均值当全部结论:平均 FPS 会掩盖最大连续丢帧,平均时延会掩盖 P95/P99 尖峰。

相关文档

      • RN 性能调优之滑动卡顿问题介绍(系列第三篇)

      • RN 性能调优之点击响应和完成时延分析介绍(系列第二篇)

----------------------------------------------------------------------------------------------------------

🔗 官网开发者学堂视频:https://developer.huawei.com/consumer/cn/training/result?type2List=201783644516849879&orderBy=1&courseType=5?ha_source=zxqy-IT&ha_sourceId=89000468

🔗 社区DFX专题文章: https://developer.huawei.com/consumer/cn/forum/subject/2101218731402391001?ha_source=zxqy-IT&ha_sourceId=89000468

【扫码加入 HarmonyOS DFX 技术交流群】


©本站发布的所有内容,包括但不限于文字、图片、音频、视频、图表、标志、标识、广告、商标、商号、域名、软件、程序等,除特别标明外,均来源于网络或用户投稿,版权归原作者或原出处所有。我们致力于保护原作者版权,若涉及版权问题,请及时联系我们进行处理。
分类
HarmonyOS
地址:北京市朝阳区北三环东路三元桥曙光西里甲1号第三置业A座1508室 电话:13391790444或(010)62178877
版权所有:电脑商情信息服务集团 北京赢邦策略咨询有限责任公司
声明:本媒体部分图片、文章来源于网络,版权归原作者所有,我司致力于保护作者版权,如有侵权,请与我司联系删除

京ICP备:2022009079号-2

京公网安备:11010502051901号

ICP证:京B2-20230255