一文读懂直播卡顿提升那些事儿

宿愿本文可以带给大家一个相对全局的视角看待卡顿疑问,意识到卡顿是什么、卡顿的成因、卡顿的分类、卡顿的提升和一些阅历积攒,对症下药地处置 App流利性疑问。接上去会从以下五个方面启动讲述:

1. 什么是卡顿

卡顿,望文生义就是用户体感界面不流利。咱们知道手机的屏幕画面是依照必定频率来刷新的,通常上讲,24帧的画面更新就能让人眼觉得是连接的。但是实践上,这个只是针对普通的视频而言。关于一些强交互或许较为敏感的场景来说,比如游戏,最少要求 60 帧,30帧的游戏会让人觉得不适;位移或许大幅度动画 30 帧会有清楚顿挫感;跟手动画假设能到 90 帧甚至 120帧,会让人觉得十分细腻,这也是近来厂商主打高刷牌的要素。

关于用户来说,从体感角度大抵可以将卡顿分为以下几类:

这些体验关于用户可以说是十分蹩脚的,甚至会惹起感官的焦躁,进而造成用户不情愿继续逗留在咱们的 App。可以说,流利的体验关于用户来说至关关键。

2. 为什么会出现卡顿

用户体感的卡顿疑问要素很多,且经常是一个复合型的疑问,为了聚焦,这里暂只思索真正意义上的掉帧卡顿。

2.1 绕不开的 VSYNC

咱们通常会说,屏幕的刷新率是 60 帧,要求在 16ms 内做完一切的操作才不会形成卡顿。但是这里要求明白几个基本疑问:

这里先回答第一个疑问:为什么是 16ms。早期的 Android 是没有 vsync 机制的,CPU 和 GPU 的配合也比拟凌乱,这也形成驰名的tearing 疑问,即 CPU/GPU 直接更新正在显示的屏幕 buffer 形成画面撕裂。后续 Android 引入了双缓冲机制,但是 buffer的切换也要求一个比拟适宜的机遇,也就是屏幕扫描完上一帧后的机遇,这也就是引入 vsync 的要素。

早先普通的屏幕刷新率是 60fps,所以每个 vsync 信号的距离也是 16ms,不过随着技术的更迭以及厂商关于流利性的谋求,越来越多 90fps 和120fps 的手机面世,相对应的距离也就变成了 11ms 和 8ms。

那既然有了 VSYNC,谁在消费 VSYNC?其实 Android 的 VSYNC 消费者有两个,也就对应两类 VSYNC 信号,区分是VSYNC-app 和 VSYNC-sf,所对应的也是下层 view 绘制和 surfaceFlinger 的分解,详细的咱们接上去详细说。

这里还有一些比拟无心思的点,有些厂商会有 vsync offset 的设计,App 和 sf 的 vsync 信号之间是有偏移量的,这也在必定水平上使得App 和 sf 的协同效应更好。

2.2 View 流离失所的永世

在讲下一 part 之前先引入一个话题:

一个 view 终究是如何显示在屏幕上的?

咱们普通都比拟了解 view 渲染的三大流程,但是 view 的渲染远不止于此:

此处以一个通用的配件减速流程来表征

Google 将这个环节划分为:其余期间/VSync 提前、输入处置、动画、测量/规划、绘制、同步和上行、命令疑问、替换缓冲区。也就是咱们罕用的 GPU严厉形式,其实情理是一样的。到这里,咱们也就回答进去了第二个疑问:16ms 内都要求成功什么?

准确地说,这里仍可以进一步细化:16ms 内成功 APP 侧数据的消费;16ms 内成功 sf layer 的分解

View 的视觉成果正是经过这一整条复杂的链路一步步展现进去的,有了这个前提,那就可以得出一个论断:上述恣意链路出现卡顿,均会形成卡顿。

2.3 消费者和消费者

咱们再回到 Vsync 的话题,消费 Vsync 的双方区分是 App 和 sf,其中 App 代表的是消费者,sf代表的是消费者,两者交付的两边产物则是 surface buffer。

关于普通的消费者和消费者形式,咱们知道会存在相互阻塞的疑问。比如消费者速度快但是消费者速度慢,亦或是消费者速度慢消费者速度快,都会造成全体速度慢且形成资源糜费。所以Vsync 的协同以及双缓冲甚至三缓冲的作用就表现进去了。

思索一个疑问:能否缓冲的个数越多越好?过多的缓冲会形成什么疑问?

答案是会形成另一个重大的疑问:lag,照应提前

这里联合 view 的永世,咱们可以把两个流程合在一同,让咱们的视角再高一层:

2.4 机制上的包全

这里咱们来回答第三个疑问,从系统的渲染架构过去说,机制上的包全关键有几方面:

这些机制上的包全在系统层面最大水平地保证了 App体验的流利性,但是并不能帮咱们彻底处置卡顿。为了提供愈加流利的体验,一方面,咱们可以增强系统的机制包全,比如 FWatchDog;另一方面,要求咱们从 App的角度入手,控制运行内的卡顿疑问。

2.5 再看卡顿的成因

经过上方的讨论,咱们得出一个卡顿剖析的外围思论撑持:渲染机制中的任何流转环节出现意外,均会形成卡顿。

那么接上去,咱们一一剖析,看看都会有哪些要素或许形成卡顿。

2.5.1 渲染流程

Vsync 调度:这个是起始点,但是调度的环节会经过线程切换以及一些委派的逻辑,有或许形成卡顿,但是普通或许性比拟小,咱们也基本无法参与;

信息调度:关键是 doframe Message 的调度,这就是一个普通的 Handler 调度,假设这个调度被其余的 Message阻塞发生了时延,会直接造成后续的一切流程不会被触发。这里直播树立了一个 FWtachDog 机制,可以经过提升信息调度到达插帧的成果,使得界面愈加流利;

input 处置:input 是一次性 Vsync 调度最先口头的逻辑,关键处置 input事情。假设有少量的事情沉积或许在事情散发逻辑中参与少量耗时业务逻辑,会形成帧的时长被拉大,形成卡顿。抖音基础技术同窗也有尝试过事情采样的打算,缩小event 的处置,取得了不错的成果;

动画处置:关键是 animator动画的更新,同理,动画数量过多,或许动画的更新中有比拟耗时的逻辑,也会形成帧的渲染卡顿。对动画的降帧和降复杂度其实处置的就是这个疑问;

view处置:关键是接上去的三大流程,适度绘制、频繁刷新、复杂的视图成果都是此处形成卡顿的关键要素。比如咱们往常所说的降低页面层级,关键处置的就是这个疑问;

measure/layout/draw:view 渲染的三大流程,由于触及到遍历和高频口头,所以这里触及到的耗时疑问均会被加大,比如咱们会降不能在draw 外面调用耗时函数,不能 new 对象等等;

DisplayList 的更新:这里关键是 canvas 和 displaylist的映射,普通不会存在卡顿疑问,反而或许存在映射失败造成的显示疑问;

OpenGL 指令转换:这里关键是将 canvas 的命令转换为 OpenGL的指令,普通不存在疑问。不过这里倒是有一个可以探求的点,会不会存在一类不凡的 canvas 指令,转换后的 OpenGL 指令消耗比拟大,进而造成 GPU的损耗?有了解的同窗可以讨论一下;

buffer 替换:这里关键指 OpenGL 指令集替换给 GPU,这个普通和指令的复杂度无关。一个无心思的事儿是这里一度被咱们作为线上采集 GPU目的的数据源,但是由于多缓冲的要素数据准确度不够被丢弃了;

GPU 处置:望文生义,这里是 GPU 对数据的处置,耗时关键和义务量和纹理复杂度无关。这也就是咱们降低 GPU 负载有助于降低卡顿的要素;

layer 分解:这里关键是 layer 的 compose 的上班,普通接触不到。偶然发现 sf 的 vsync 信号被 delay 的状况,形成buffer 供应不迭时,临时还不清楚要素;

光栅化/Display:这里临时疏忽,底层系统行为;

Buffer 切换:关键是屏幕的显示,这里 buffer 的数量也会影响帧的全体提前,不过是系统行为,不无能涉。

2.5.2 视频流

除了上述的渲染流程惹起的卡顿,还有一些其余的要素,典型的就是视频流。

2.5.3 系统负载

2.6 卡顿的分类

咱们此处再全体整顿并归类,为了更完备一些,这里将推流也放了过去。在必定水平上,咱们遇到的一切卡顿疑问,均能在这里找到通常依据,这也是指点咱们提升卡顿疑问的通常撑持。

3. 如何评估卡顿

3.1 线上目的

3.2 线下目的

Diggo是字节自研的一个放开的开发调试工具平台,是一个集「评估、剖析、调试」为一体的,一站式工具平台。内置性能测评、界面剖析、卡顿剖析、内存剖析、解体剖析、即时调试等基础剖析才干,可为产品开发阶段提供弱小助力。

4. 如何提升卡顿

4.1 罕用的工具

4.1.1 线上工具
4.1.2 线下工具

4.2 罕用的思绪

这里关键针对 UI 卡顿和 UI/流相互影响打来的卡顿。

关于 UI 卡顿来说,咱们手握卡顿提升的 8 板大斧子,所向无敌:

总体思绪就是「能不干就不干、能少干就少干、能早点干就早点儿干、能正点儿干就正点儿干、能让他人干就让他人干、无能完一次性当 10次就只干一次性,真实不行,再思索自己大干一场」。

这里例举出一些经常出现的提升思绪,留意这必定也无法能是所有,假设有其余好的提升思绪,咱们可以一同交流。

4.3 一些做过的事儿

4.3.1 处置 UI 卡顿惹起的流卡顿

直播关于 SurfaceView 的切换是一个常年的专项,分为多期逐渐将 SurfaceView在直播全量落地,场景笼罩秀场直播、聊天室、游戏直播、电商直播、媒体直播等,业务上关于浸透率和逗留时长有比拟清楚的收益,同时功耗的收益也很可观。

这里是一个掂量的疑问,SurfaceView 的兼容性疑问 pk 带来的收益能否能打平,普通来说,越是复杂的业务场景,收益约大。

4.3.2 处置 message 调度

FWatchDog 是基于对 MessageQueue 的调度战略和同步屏障原理,以均帧耗时为阈值判定丢帧后被动在 MessageQueue中拔出同步屏障,保证渲染异步 message 和 doframe 的优先口头,到达一种渲染插帧的成果,同时具有 ANR智能复原同步屏障的才干,保证打散的有效。

所以 FWatchDog 和打散是好的伙伴,能发生 1+1 大于 2 的成果。

4.3.3 缩小口头次数

一个典型的运行场景就是滑动场景的 GC克服,能够清楚提高用户高低滑的经常使用体验。这个场景置信每个业务都会存在,特意是存在少量遍历的逻辑,提升成果清楚。

4.3.4 代码下线

一些老的框架、无用的逻辑以及存在性不高的代码都可以下线,这里基本业务强关系,就不举详细的例子了。

4.3.5 处置耗时函数(打散/异步)

首先是打散,直播做了很多 task 的拆分以及打散,第一可以减轻渲染帧的耗时压力,第二可以和 FWatchDog联合到达插帧的成果。这里其实还可以控制 task 的口头优先级,包含队列的插队等,总之 MessageQueue 的合理调度是很有必要的。

异步的经常使用也相对比拟多,一个埋点日志的框架,以及一些 inflate 的加载等,都可以经常使用异步来处置卡顿疑问。

4.3.6 预热

直播提供了一个预热框架,可以让直播外部的一次性性老本逻辑获取在宿主侧口头的时机,同时提供完备的队列优先级控制、同步异步控制和 task生命周期控制,降低直播外部初次加载的卡顿疑问。

4.3.7 配件减速

拉高配件的运转性能,比如 CPU 频率、GPU 频率、线程绑大核以及网络关系的调优,从底层提高 App 的运转体验。

您可能还会对下面的文章感兴趣: