卡顿的本质
iOS 屏幕每 16.67ms 刷新一次(120Hz 设备是 8.33ms)。一帧内的工作没做完,就会错过刷新,表现为掉帧。所以排查卡顿,核心就一个问题:这一帧的时间被谁用掉了?
拆开来看只有三个环节:主线程、渲染、GPU。
第一问:主线程忙不忙?
主线程负责布局、图片解码、文本排版。这些事任何一件超过 16ms,直接掉帧。
常见的大头:
- Auto Layout:复杂视图层级下约束求解很慢,列表滚动时反复触发更严重。
- 图片解码:不预先解码,第一次显示时主线程解码,大图直接破帧。
- 圆角和阴影:会触发离屏渲染,CPU 要先画一份额外图像再合成。
- 富文本排版:多行文本、动态字体,排版计算不便宜。
怎么解决?原则只有一个:能提前做的别拖到主线程当下做。图片异步解码、圆角预先画好、布局结果缓存、文本排版预计算。
第二问:渲染准备有没有坑?
主线程干完活,Core Animation 要把更新打包交给 GPU。这一步的坑比较隐蔽:
- 视图层级太深:几十层 view 叠在一起,每层都有固定成本。
- 半透明太多:透明视图需要混合计算,大面积叠加会明显变慢。
- 重写了 drawRect:一旦重写,就绕开 GPU 走 CPU 绘制,能不用就不用。
排查方法很简单,Simulator 里打开 Color Blended Layers,绿色正常,红色就是要优化的混合区域,让红色尽量消失。
第三问:GPU 扛得住吗?
GPU 的负载看两个数:设备利用率和 Tile 利用率。
设备利用率接近 100%,GPU 已经满了;Tile 利用率超过 85%,多半是纹理问题——纹理太大、没压缩、没用 Mipmap。
优化方向:
- 大图用 ASTC 压缩格式
- 不透明 view 设置
isOpaque = true,减少无效绘制 - 减少离屏渲染的触发
别只看 FPS
FPS 是一秒内的平均值,会掩盖问题。一秒内前 30 帧 8ms、后 30 帧 25ms,平均还是 55 FPS,但用户会感到明显卡顿。
真正该关注的是帧间隔的稳定性。单帧延迟的尖峰,才是卡顿的真实来源。高刷设备上尤其明显。
排查顺序
- 看帧延迟曲线,确认卡顿是周期性还是无规律
- 看主线程占用,判断是不是 CPU 瓶颈
- 看 GPU 利用率,判断是不是 GPU 瓶颈
- 针对具体环节优化,改完对比帧延迟分布,而不是只看 FPS
核心就一句话:每一帧都赶上车,比平均速度好看更重要。
0 个评论
要回复文章请先登录或注册