qq怎么升级升得快,qq怎么升级最新方法

首页 > 娱乐 > 作者:YD1662024-05-01 17:07:20

Instruments 分析 QQ 启动耗时图

什么是主线程抢占(Preempted)问题?简单来说就是主线程的 CPU 时间片被其他线程抢占,导致主线程得不到 CPU 资源。随着抢占问题越来越严重,也引出一些相关的问题,例如启动总耗时也随着劣化、启动后卡顿、启动耗时波动大、防劣化性能报告误判概率增大等。

为什么会出现主线程被抢占?简单来说有以下几个原因:

  1. 系统调度行为、系统级线程(比如 PageIn 线程)抢占。
  2. APP 频繁开辟子线程却不注意管理子线程的数量,可能会出现「线程爆炸」的情况,而且子线程不恰当地设置 QoS,会容易导致主线程被抢占。
  3. 主线程任务过重,占用时间片过长,会被系统惩罚降级,然后被其他子线程抢占。

了解了原因以后,我们从以下三个方面进行治理:

减少子线程的数量

手 Q 大部分业务广泛使用 GCD,经过查找资料和研究,我们发现频繁使用 GCD 的全局队列,可能会导致线程爆炸,原因是当子线程在 sleep/wait/lock 状态时,会被 GCD 认为是非活跃的状态,当有新的任务到来时可能便会创建新的线程。

qq怎么升级升得快,qq怎么升级最新方法(5)

Apple 工程师、前 GCD 开发工程师发表言论

苹果官方建议不要创建大量队列,使用 target_queue 设置队列的层级结构,多个子系统就形成了一个队列的树状结构,最后队列底层使用串行队列作为 target_queue 。详情见《Modernizing Grand Central Dispatch Usage - WWDC17》

降低子线程 QoS

如果全局队列 QoS 设置为 DISPATCH_QUEUE_PRIORITY_DEFAULT ,则该任务的 QoS 将继承原来所在队列的 QoS (如果原来队列是主队列,将从 QOS_CLASS_USER_INTERACTIVE 降低为 QOS_CLASS_USER_INITIATED)。开发同学经常在主线程将任务派发到全局队列,并指定 QoS 为 DISPATCH_QUEUE_PRIORITY_DEFAULT ,这将导致存在大量子线程 QoS 为 QOS_CLASS_USER_INITIATED。以下是 QoS 优先级排序:

__QOS_ENUM(qos_class, unsigned int, QOS_CLASS_USER_INTERACTIVE = 0x21, // 33 QOS_CLASS_USER_INITIATED = 0x19, // 25 QOS_CLASS_DEFAULT = 0x15, // 21 QOS_CLASS_UTILITY = 0x11, // 17 QOS_CLASS_BACKGROUND = 0x09, // 9 QOS_CLASS_UNSPECIFIED = 0x00, // 0 );

而实际开发中,很多网络请求、写磁盘 I/O,都使用了该 QoS,实际上是可以通过降低 QoS 来降低子线程的优先级。

提高主线程的优先级

QoS 并不完全等价于最终的线程优先级,主线程优先级范围为 29~47 。为什么运行过程中主线程优先级会变化?官方文档 《Mach Scheduling and Thread Interfaces》中的 “Why Did My Thread Priority Change? ” 章节解释了这个原因:如果线程的运行超出了其分配的时间而没有被阻塞,则会受到惩罚甚至被降低优先级,这么做的目的就是为了避免高优先级的线程一直抢占系统资源,导致低优先级的线程一直处于饥饿的状态。

如何避免主线程运行超出 CPU 分配时间,而免除降级惩罚?可以从 RunLoop 层面做减负。

App 启动过程开始的第一个 RunLoop,会执行持续到首屏渲染结束。而首屏的任务一般很重,导致 RunLoop 耗时很长,容易被系统降级。

qq怎么升级升得快,qq怎么升级最新方法(6)

QQ 启动时第一个 Runloop 耗时示意图

解决方案是对第一个 RunLoop 里的任务做拆分。我们的做法是保留必要的全局初始化逻辑在第一个 RunLoop 中,把主 UI 的创建延迟到下一个 RunLoop 里。这样不仅有效地解决了启动时主线程被抢占的情况,还能够加速启动更快看到主页面。

其实这里还有一些优化空间,我们将第一个 RunLoop 的任务都挪到第二个 RunLoop 了,就又导致第二个 RunLoop 耗时较大,可以按照此思路继续优化。

2.2 "众"享丝滑 — 性能流畅度提升

2.2.1 如何定义流畅?

流畅(丝滑),体感上的表现是屏幕内容跟随手指操作即时变化,每一次操作都即时地反馈在屏幕上。如图所示,未开启高刷帧率时应保证 16.67ms 内将用户操作更新至屏幕上。

qq怎么升级升得快,qq怎么升级最新方法(7)

用户每个操作,都需经历图中的4个步骤,任一步骤时间过长,都会无法及时更新画面造成卡顿。来源:《Advanced Graphics and Animation Performance》

让 App 做到每 16.67 毫秒更新一次用户操作很难吗?难,难在这么短的时间内 CPU 和 GPU 需要完成很多事情,更具体的:

主线程的 16.67 毫秒 - 系统需要的耗时 = 开发者可用的时间。如下图所示,蓝色区域为开发者占用的时间,当开发者使用的时间过长即会造成 hang,即卡顿。

qq怎么升级升得快,qq怎么升级最新方法(8)

上一页12345下一页

栏目热文

文档排行

本站推荐

Copyright © 2018 - 2021 www.yd166.com., All Rights Reserved.