页面滑动过程卡顿,不流畅。

在上述渲染流程中,如果本次Vsync信号到来时,应用侧或者Render Service侧相关流程的执行时间超过11.1ms,未在下一次Vsync信号到来时执行完本次的渲染流程,会造成两次Vsync信号到来时仅执行一次渲染流程,出现丢帧。如果存在多次丢帧的情况,用户会感知到卡顿的现象。
常见Trace关键字如下:
关键字 | 说明 |
|---|---|
H:FlushDirtyNodeUpdate | 刷新标脏的组件,当状态变量变化时,比如宽度和高度,组件需要重新布局刷新 |
H:CustomNodeUpdate 组件名 | 组件刷新,当状态变量变化时触发 |
H:CreateTaskMeasure[组件名][self:组件ID][parent:父组件ID] | 创建组件的测量任务,确定组件的宽、高 |
H:CreateTaskLayout[组件名][self:组件ID][parent:父组件ID] | 创建组件的布局任务,确定组件的位置 |
H:Create[组件名][self:组件id] | 组件创建 |
H:SendCommands | 发送指令,通知图形侧进行渲染。下方H:MarshRSTransactionData表示提交渲染数据给渲染服务 |
H:HandleOnAreaChangeEvent | 处理组件区域变化事件,组件的大小、位置发生时触发。 |
H:HandleVisibleAreaChangeEvent | 处理可见区域变化事件,组件可见面积(即组件在屏幕显示区的面积,只计算父组件内的面积,超出父组件部分不会计算)与组件自身面积的比值与设置的阈值接近时触发。 |
H:LazyForEach predict | LazyForEach预处理 |
H:List predict | List预处理 |
H:Builder:BuildLazyItem | 构建LazyItem |
H:CustomNode:BuildItem[组件名][self:组件ID][parent:父组件ID] | 构建自定义组件 |
H:ExecuteJS | 运行ArkTS业务逻辑 |
H:ViewPU.viewPropertyHasChanged 组件名 状态变量名 N | 状态变量更新,N表示该状态变量更新后影响的组件数量。该Trace关键字需要运行hdc shell param set persist.ace.debug.enabled 1命令然后重启应用才能生效 |
H:JSAnimation | 执行显示动画 |
H:Napi complete | 执行Napi接口函数的回调函数 |
binder transaction | 同步binder调用 |
H:DispatchDisplaySync | 帧回调函数执行 |
H:aboutToBeDeleted | 组件析构时执行,在未使用复用机制时,FlushDirtyNodeUpdate和LazyForEach predict下会析构组件,导致刷新时组件重复创建 |
ArkUI页面滑动卡顿丢帧问题的定位思路如下:

使用DevEco Profiler Frame工具录制滑动卡顿丢帧过程,相关步骤可以参考创建深度分析任务并进行录制。如果已有待分析的Trace文件,可以参考会话区中数据导入的步骤,将文件导入DevEco Profiler中查看分析。
如下图为搜索Trace关键字H:APP_LIST_FLING的示例,其中H:APP_LIST_FLING为示例应用(包名为com.example.myapplication,Trace中简写为e.myapplication)的滑动泳道,泳道中有颜色部分(图中为紫色)为页面滑动过程。点击H:APP_LIST_FLING泳道右侧星型按钮将泳道置顶,方便问题分析。

找到Frame泳道后点击左侧箭头展开,查看子泳道是否存在数据。
根据H:APP_LIST_FLING泳道中的Trace点框选滑动过程的数据,点击Display泳道确认滑动过程的屏幕刷新率,如下图中可看到屏幕刷新率为120Hz左右(Avg Hz为119),则Vsync信号周期为8.3ms,如果应用侧或Render Service侧未在8.3ms内执行完渲染流程,会引起丢帧。

通过App Frame(如e.myapplication的下方)和RS Frame(render_service下方)标签的泳道中可分别确认应用、Render Service卡顿丢帧的位置,出现卡顿丢帧(未在8.3ms执行完渲染流程)的地方显示为红色,正常完成渲染(在8.3ms内执行完渲染流程)的帧显示为绿色。
如下图可看到应用(e.myapplication)存在几处卡顿丢帧,点击红色部分,然后点击"Details"区域"Corresponding Slice"下方左侧的箭头跳转到应用主线程泳道,结合App Frame卡顿丢帧处(红色部分)以及应用主线程的Trace信息,可以分析应用卡顿丢帧的原因。


在滑动范围中,Present Fence泳道上缺少Trace点H:Waiting for Present Fence的部分(下图方框中空白的部分),很可能是存在丢帧问题,需要结合应用侧、Render Service侧主线程的Trace信息确认。

如下图为应用侧卡顿丢帧的示例(屏幕刷新率为120Hz),可看到应用泳道(e.myapplication)存在卡顿帧(红色),而render_service泳道无卡顿帧(绿色)。应用泳道的FPS值为87.6,远少于120,应用侧存在卡顿丢帧,而render_service泳道的FPS值少于120是应用侧发生丢帧,提交绘制相关数据较晚导致。

如下图为Render Service卡顿丢帧的示例(屏幕刷新率为120Hz),可看到应用泳道无卡顿帧(绿色),而render_service泳道存在卡顿帧(红色)。应用泳道的FPS值为122.0,而render_service泳道的FPS值为11.9,远少于120,Render Service进程存在卡顿丢帧。
如下图为应用侧卡顿丢帧的示例,可看到应用泳道中卡顿丢帧区域(方框部分)的Trace信息较宽且相连到一块,而右侧未丢帧处的Trace点较短且均匀分布。

如下图为Render Service卡顿丢帧的示例,可看到应用泳道中的Trace信息较短且均匀分布,而render_service泳道的Trace信息较宽且相连到一块。

- 11889-11889 C03947/com.exam...AceStateMgmt com.examp...lication E [(100000:100000:scope)] FIX THIS APPLICATION ERROR: @Component 'XXXXXX'[11248]: State variable 'XXXXXX' has changed during render! It's illegal to change @Component state while build (initial render or re-render) is on-going. Application error!
- 11889-11889 C03947/com.exam...AceStateMgmt com.examp...lication E [(100000:100000:scope)] FIX THIS APPLICATION ERROR: @Component 'XXXXXX'[11248]: State variable 'XXXXXX' has changed during render! It's illegal to change @Component state while build (initial render or re-render) is on-going. Application error!
- 11889-11889 C03947/com.exam...AceStateMgmt com.examp...lication E [(100000:100000:scope)] FIX THIS APPLICATION ERROR: @Component 'XXXXXX'[11248]: State variable 'XXXXXX' has changed during render! It's illegal to change @Component state while build (initial render or re-render) is on-going. Application error!
- 11889-11889 C03947/com.exam...AceStateMgmt com.examp...lication E [(100000:100000:scope)] FIX THIS APPLICATION ERROR: @Component 'XXXXXX'[11248]: State variable 'XXXXXX' has changed during render! It's illegal to change @Component state while build (initial render or re-render) is on-going. Application error!
如没有上述大量日志打印,继续分析Frame工具抓取的Trace信息。


Trace关键字 | 含义 | 耗时多的原因 |
|---|---|---|
H:DispatchDisplaySync | 帧回调函数执行 | 帧回调函数执行耗时业务逻辑 |
H:DispatchTouchEvent | 点击事件处理 | 点击事件处理时执行耗时逻辑 |
H:FlushDirtyNodeUpdate | 标脏组件刷新 | 多个状态变量更新,大量组件刷新 |
H:UITaskScheduler::FlushTask | 刷新UI界面 | 页面组件复杂,测量、布局耗时多 |
H:HandleOnAreaChangeEvent | 执行OnAreaChange回调函数 | 回调函数中执行耗时业务逻辑 |
H:HandleVisibleAreaChangeEvent | 执行OnVisibleChange回调函数 | 回调函数中执行耗时业务逻辑 |

Trace关键字 | 含义 | 耗时多的原因 |
|---|---|---|
H:LazyForEach predict | LazyForEach预处理 | 未采用组件复用、懒加载条目构建时间长 |
H:List predict | 列表预加载 | 组件复杂,测量、布局耗时多 |
H:Preload FlowItem | 瀑布流(WaterFlow)组件的预加载 | 组件复杂,测量、布局耗时多 |

除了业务代码耗时多,可能的情况还有执行同步binder调用(Trace点为binder transaction)耗时多、Napi接口函数的回调函数执行耗时多(Trace点为H:Napi complete)等,可以查看ArkTS Callstack和Callstack泳道的调用栈来确认相关代码,定位耗时函数。
Render Service渲染进程卡顿丢帧,可查看render_service进程的RSUniRenderThread泳道是否存在单帧耗时长的情况。
如下图可看到RSUniRenderThread泳道存在单帧耗时长(201.3ms)的情况,同时存在Trace点H:onCreateTexture,在绘制时创建8191*7176大小的纹理。

在hilog日志中搜索CreatePixelMapExtended查看应用是否有创建像素图,如下日志示例中可以看到创建10800*7176的高分辨率图片,memoryType值为2表示采用共享内存,而不是DMA内存,导致Render Service渲染进程卡顿丢帧。
- 3551-27643 C02B61/com.exa...n/ImageSource com.examp...lication I CreatePixelMapExtended success, imageId:1769788704094294, desiredSize: (0, 0), imageSize: (10800, 7176), desiredHdr: 1, hdrType : 1, memoryType : 2, cost 427949 us
ArkUI页面滑动卡顿丢帧的原因有: