结合 RunLoop 和 Instrument 定位卡顿
iOS 应用,丝般顺滑的理想情况就是 60FPS (对于 iPad Pro 是 240FPS),即在 16ms 之内完成一次渲染。如果找到在每次渲染花费了多久,究竟做了什么事情,那么就可以进行针对性的优化。
RunLoop 的概念
在程序中,我们需要一种机制,可以让当前线程能够随时处理事件但不退出。这种模型通常被称为 Event Loop,在 iOS 中使用 RunLoop 来实现。
RunLoop 管理了所在线程需要处理的事件和消息。当有事情需要处理时,就唤醒当前线程,处理事件。当事情全部处理完毕时,线程处于休眠状态,以避免资源占用。这样子线程一直处于“接受消息->等待->处理”循环中。

根据苹果文档,RunLoop 的内部逻辑如上。RunLoop 有很多种状态,比如 beforeWaiting
、afterWaiting
,当状态发生改变时,就会通知 observer。而触摸事件、定时器、网络请求返回等都是作为 Source0、Source1、Timer 被加到需要处理的队列中,都可以唤醒当前线程的 RunLoop。
RunLoop 与界面更新
当在操作 UI 时,比如改变了 Frame、更新了 UIView/CALayer 的层次时,或者手动调用了 UIView/CALayer 的 setNeedsLayout/setNeedsDisplay方法后,这个 UIView/CALayer 就被标记为待处理,并被提交到一个全局的容器去。
苹果注册了一个 Observer 监听 BeforeWaiting(即将进入休眠) 和 Exit (即将退出Loop) 事件,回调去执行一个很长的函数:
_ZN2CA11Transaction17observer_callbackEP19__CFRunLoopObservermPv()。这个函数里会遍历所有待处理的 UIView/CAlayer 以执行实际的绘制和调整,并更新 UI 界面。
即界面更新一定发生在主线程的 RunLoop BeforeWaiting 状态发生时。那么我们可以得出一个结论,如果主线程的 RunLoop 当前事件循环占用的时间过多,超过了 32 ms,那么一定会发生一次掉帧。
Point of Interest
iOS 10 之后,引入了一个新的 API,kdebug_signpost_start
与 kdebug_signpost_end
。可以结合 Instrument 的 Point of Interest 功能,用来分析起始到结束的耗时。
//事件段的起始和结束
// Timing an activity (code 7 - "Start Up")
kdebug_signpost_start(7, 0, 0, 0, 0);
[self loadAssets];
kdebug_signpost_end(7, 0, 0, 0, 0);
具体使用方法如上,其中第一个参数用来标识事件的 ID,可以同时分析多个事件。如果某个事件发生了多次,那么就可以得到一个列表,以及这个事件耗时的统计信息。

选择列表中的某个点以后,右键选择,可以过滤掉其他时间的信息。

这样子,结合 Time Profile 功能,就可以看到某个事件耗时,以及究竟哪些代码耗时。
结合 RunLoop 与 Point of Instrument 功能
为主线程的 RunLoop 增加一个 observer,并监听特定的状态变化,就找出每一个 RunLoop 循环究竟花费了多长事件。

使用 Instrument,可以得到下面的图。

这样子可以看到每一个 RunLoop 耗时多少,耗时在哪里。找出 Top 问题,针对性优化。
System Trace
time profile 只是查看 CPU 的执行情况,如果一个线程长时间得不到调度,在 time profile 里得不到相应的信息。这时需要用到 System Trace 这个工具。
使用 system trace 时,会记录最近 5s 的 kernel trace,然后分析 Scheduling activity、System calls、Virtual memory operations 等信息。如果可以卡顿可以复现,那么就可以找出来锁等待、死锁、系统调用造成的卡顿问题。
如下图就是由于线程调度造成的卡顿问题。可以看到主线程被 block 了 1 秒多,原因是调用了 AudioSession 相关的函数。

利用 RunLoop 进行优化
找到每一个 RunLoop 中耗时之后,就可以针对性优化,比如主线程读写、懒加载、异步布局之类。也可以把比较复杂的任务分解到不同的 RunLoop 中,这样子 RunLoop 循环的时间不会太长,可以更快响应事件。
具体做法可以参考 texture
这个组件。下面是 copy 过来的代码。
为主线程的 RunLoop 增加一个 Source
_runLoopSource = CFRunLoopSourceCreate(NULL, 0, &sourceContext);
CFRunLoopAddSource(runloop, _runLoopSource, kCFRunLoopCommonModes);
如果需要,把事件加入一个队列中,等待下一个 RunLoop 处理
[renderQueue enqueue:node];
Runloop 进入
kCFRunLoopBeforeWaiting
状态时,判断队列中是否有待处理的事情。如果有,唤醒 Source,使得 RunLoop 马上进入下一个时间循环if (!isQueueDrained) {
CFRunLoopSourceSignal(_runLoopSource);
CFRunLoopWakeUp(_runLoop);
}
参考
结合 RunLoop 和 Instrument 定位卡顿的更多相关文章
- UE手游如何应对CPU帧率瓶颈和卡顿?
如何高效准确详细的对性能进行剖析?腾讯游戏学院专家Leonn将归纳总结在UE下对每一性能指标的剖析方法,本文重点讲解如何应对CPU帧率瓶颈和卡顿? CPU上帧率低和卡顿是性能优化中最易出现的一部分,尤 ...
- APP测试工具之TraceView卡顿检测
Traceview卡顿检测 Traceview是Android平台特有的数据采集和分析工具,集成在DDMS工具中,可以采集程序中的方法执行耗时.调用关系.调用次数以及资源占用等情况. 一.使用方法 1 ...
- 想让安卓app不再卡顿?看这篇文章就够了
欢迎大家前往腾讯云+社区,获取更多腾讯海量技术实践干货哦~ 本文由likunhuang发表于云+社区专栏 实现背景 应用的使用流畅度,是衡量用户体验的重要标准之一.Android 由于机型配置和系统的 ...
- iOS 性能优化总结
卡顿产生的原因 在 VSync信号到来后,系统图形服务会通过 CADisplayLink等机制通知 App,App主线程开始在 CPU中计算显示内容,比如视图的创建.布局计算.图片解码.文本绘制等.随 ...
- 80.Android之内存管理
转载:http://www.jianshu.com/p/9fb0a795da93 1. Android中的内存 1.1 Android中的垃圾回收机制 Android 平台最吸引开发者的一个特性:有垃 ...
- 【行业交流】2016 TiD质量竞争力大会——移动互联网测试到质量的转变之路
◆版权声明:本文出自胖喵~的博客,转载必须注明出处. 转载请注明出处:http://www.cnblogs.com/by-dream/p/5691233.html TiD质量大会在北京召开,有幸去参加 ...
- android app性能优化大汇总(UI渲染性能优化)
UI性能测试 性能优化都需要有一个目标,UI的性能优化也是一样.你可能会觉得“我的app加载很快”很重要,但我们还需要了解终端用户的期望,是否可以去量化这些期望呢?我们可以从人机交互心理学的角度来考虑 ...
- Android UI性能优化详解
设计师,开发人员,需求研究和测试都会影响到一个app最后的UI展示,所有人都很乐于去建议app应该怎么去展示UI.UI也是app和用户打交道的部分,直接对用户形成品牌意识,需要仔细的设计.无论你的ap ...
- Python爬取CSDN博客文章
0 url :http://blog.csdn.net/youyou1543724847/article/details/52818339Redis一点基础的东西目录 1.基础底层数据结构 2.win ...
随机推荐
- word2vec相关资源
word2vec官网:https://code.google.com/p/word2vec/ 利用中文数据跑Google开源项目word2vec:http://www.cnblogs.com/hebi ...
- 【原型实战】分分钟搞定Unsplash网站原型设计
网站原型设计是我们在设计网页过程中必不可少的一步,激烈的市场竞争让我们不得不对产品进行快速迭代,如何高速有效的进行原型设计成为了设计师头疼的问题.本文将以unsplash网站为实例,教大家快速搞定we ...
- 创建WRAPPER时, SQL20076N 未对指定的操作启用数据库的实例。
您可以通过运行DB2 UPDATE DBM CFG USING FEDERATED YES来设置这个参数.修改这个参数后,必须重新启动实例才会生效(DB2STOP/DB2START).所以你会出现你的 ...
- mac安全与隐私只有两个选项,少了一个任何来源
很多软件安装后就会出现,程序已损坏,请移到废纸篓的提示. 解决方法:在终端里输入:sudo spctl --master-disable 然后回车,然后输入密码,即可在安全选项中看到重新出现的允许任何 ...
- 破解Unity5.3.4f1
破解的目的是将受限的个人版变为全功能的Pro版,破解后就可以使用所有功能了,界面也变成了黑色的主题. 破解网址(支持最新版的5.3.4f1): http://www.ceeger.com/forum/ ...
- js级联出生日期
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...
- 用jQ实现一个简易计算器
HTML和CSS结构: <!DOCTYPE html> <html lang="en"> <head> <meta charset=&qu ...
- bootstrap 问题
less; sass: css预处理:可以直接使用.css,也可以修改.less,生成定制化的css CDN: 服务,使用这个效果会更好.theme一般不引入,jquery一般在js之前引入. 使用b ...
- SQL Server 索引基本概念与优化
数据页和区 页 SQL Server 中的数据以“页”(Page)的形式保存数据,页是SQL Server 的IO单位,读/写一次至少是一页.一页为8K(8192byte). 页由三部分组成,页头,数 ...
- 基于tinyproxy搭建代理服务器
在我们实际的工作当中,经常会遇到这种情况,我们对线上服务器进行操作时是通过跳板机来进行的,出于安全性及投入资金来考虑非必要情况下除跳板机以外的服务器是没有内网ip的,所以当我们位于内网的服务器需要使用 ...