QQ空间掉帧率优化实战

商业转载请联系腾讯WeTest得到受权,非商业转载请注明出处。缓存

 

WeTest 导读安全

空间新业务需求日益增多,在业务开发阶段的疏忽,或者是受到其余业务的影响(好比一些非空间的业务网络回包或者逻辑在主线程进行),致使空间的某些页面掉帧率上升。微信


 

 

本文从两个方向介绍优化掉帧率:网络

●  Time Profiler时间分析工具多线程

●  一些优化手段app

 

                                                                                Time Profiler(Xcode 9.1)异步

 

 

Time Profiler分析原理:它按照固定的时间间隔来跟踪每个线程的堆栈信息,经过统计比较时间间隔之间的堆栈状态,来推算某个方法执行了多久,并得到一个近似值。
 

 

 

 

下面是Time Profiler的界面说明和一些使用建议。ide

 

 

 

一、主线程使用波峰函数

 

开始模拟用户使用App的时候,能够看到主线程的使用状况,它的波峰会忽高忽低,说明app正在进行耗时计算/正常计算,咱们能够截取不一样时间段的波峰区间进行探究,好比刚进入空间的5秒内,或者拉取到新feeds流以后平缓的5秒等不一样场景(小tips:使用触控板向左右两边挪动能够进一步细化时间区间)工具

 

二、关于筛选面板的使用

 

●  Separate by State:此选项会根据应用程序的生命周期状态对结果进行分组,而且是检查应用程序在多大程度上执行以及什么时候执行的有用方法。

 

●  Separate by Thread:根据线程类别分开,方便查看哪些线程占用了最大的CPU。

 

●  Invert Call Tree:调用树倒返过来,将习惯性的从根向下一级一级的显示,如选上就会返过来从最底层调用向一级一级的显示。若是想要查看那个方法调用为最深时使用会更方便些。

 

●  Hide System Libraries:选上它只会展现与应用有关的符号信息,通常状况下咱们只关心本身写的代码所需的耗时,而不关心系统库的CPU耗时。(可是不少咱们的代码每每是由系统的函数进来,隐藏的话每每可能会丢失很重要的信息)

 

●  Flatten Recursion:将递归函数视为每一个堆栈跟踪中的一个条目,而不是多个。

 

●  Top Functions:将花费在函数中的总时间视为直接在该函数内的时间总和以及该函数所调用的函数花费的时间。若是函数A调用B,那么A的时间被报告为A的时间而且加上在B中花费的时间。

 

为了能够获取更多的信息,建议只勾选 “Separate by Thread”

 

三、操做小技巧

在折叠的堆栈,按住“alt”点开旁边的三角形便可展开所有折叠堆栈,若是发现耗时严重的堆栈中,能够右键点开菜单,选中“Reveal in Xcodes”便可跳转到对应的代码区域 。

 

 

                                                                                实战应用

 

在好友动态页面来回滑动,笔者分四种状况来模拟用户的使用习惯:

●  刚进入空间(无缓存),下拉刷新

●  刚进入空间(有缓存),下拉刷新

●  来回滑动

●  上拉加载更多

 

一、将耗时操做(如文件IO)放到工做线程

 

在咱们读取Gif首帧的时候,-[QZoneGIFDecode firstFrameWithURL:viewSize:]里面是有一部是从磁盘里读取二进制文件而且转换成NSData,而后再进行解码,这部分的IO操做优化后是放到了工做线程,异步读取完成解码以后再展现图片,不阻塞主线程。

 

 

再举一个例子:异步解析网络回包数据和异步排版

 

将耗时操做放到工做线程异步执行占了优化工做的大头,在这个过程当中,要注意多线程问题,好比线程安全问题、死锁、野指针等,好比容器类的读写操做,最经常使用的NSMutableArray, NSMutableDictionary等, 这类集合在调用读写方法时并非线程安全,简单地在里面进行加锁操做是能够保证线程安全,不过也可能会致使其余耗时问题。

 

二、耗时函数优化

 

 

上图堆栈表示的是展现图片, 整个流程以下:

 

 

因为空间里面存在大部分图片,其中走网络下载的图片就是上述这个流程。在这个过程当中,刨开网络下载的部分,咱们会根据图片URL来存取。存取过程首先会将URL 进行MD5加密以后做为Key来进行存取,其实这一步不是必要的,并且系统提供的MD5函数比较耗时。

 

 

优化手段:

优化缓冲池存取过程,直接使用URL做为Key来存取,去掉MD5调用。

 

三、减小- (void)scrollViewDidScroll(UIScrollView *)scrollView 这个函数里面的耗时操做:

这个方法在任何方式触发 contentOffset 变化的时候都会被调用(包括用户拖动,减速过程,直接经过代码设置等),能够用于监控 contentOffset 的变化,并根据当前的 contentOffset 对其余 view 作出随动调整。可是这个方法在滚动的时候每秒调用上百次,若是在里面加入耗时操做就可能对掉帧率形成很大影响。

 

 

解决方法:优化调用耗时,或者将耗时操做放到别的地方去

 

四、提早进行(耗时操做不可避免)

在进入空间以前,咱们会有不少初始化工做,好比初始化用户的空间装扮,读取用户的一些配置等,有时候还会涉及IO操做,这部分的耗时是必不可免的。为了保证用户的体验问题,进入空间前,咱们能够提早初始化(preload),将一些耗时操做选择在适当的时机提早进行。

 

五、缓存

 

在业务上,咱们会读取一些设置项来展现或者进行不一样的功能,这些选项的即时读取多是很是耗时的(尤为是涉及非线程安全容器的读取,里面每每是利用了互斥锁或者信号量等机制保证线程安全,耗时就更加严重),咱们可使用静态变量和dispatch_once来保存起来,避免每次都去要读取一遍。

 

再举一个例子:

咱们在渲染的时候会用到不少字体颜色,每次建立这些新的字体和颜色也是耗时的一部分,咱们能够将这些UIColor和UIFont缓存起来,过程以下图:

 

 

这里还能够作进一步的优化,就是在进入空间前,把经常使用的字体生成而且缓存起来,减小渲染时再生成的耗时。

 

六、减小没必要要的操做

 

 

为了方便回溯用户的操做行为,咱们会在App里面加上不少log,通常log都涉及IO操做,不是必要的log咱们要减小,尽可能只在关键点打log。

 

七、懒加载view

不要在cell里面嵌套太多的view,这会很影响滑动的流畅感,并且更多的view也须要花费更多的CPU跟内存。假如因为view太多而致使了滑动不流畅,那就不要在一次就把全部的view都建立出来,把部分view放到须要显示cell的时候再去建立。好比:

 

 

 

八、利用主线程不一样的runloop

 

优化缓冲池存取过程,直接使用URL做为Key来存取,去掉MD5调用。

 

 

上图是进入空间的时候,须要初始化混合Cover挂件的耗时问题。

 

咱们能够利用不一样的runloop来优化这个耗时问题。主线程的 RunLoop 里有两个预置的 Mode:kCFRunLoopDefaultMode 和 UITrackingRunLoopMode。这两个 Mode 都已经被标记为"Common"属性。DefaultMode 是 App 平时所处的状态,TrackingRunLoopMode 是追踪 ScrollView 滑动时的状态。当咱们初始化挂件并加到 DefaultMode 时,这个事件 会获得重复回调,但此时滑动一个TableView时,RunLoop 会将 mode 切换为 TrackingRunLoopMode,这时 初始化挂件函数就不会被回调,于是也不会影响到滑动操做。

 

 

 

不少App会用到这个点来进行优化,好比咱们操做微信的时候,在朋友圈上拉加载更多的时候,若是不松开手是不会加载出来的,只有放开手才会展现出更多的feeds,也是利用了不一样的runloop。

 

解决掉帧的方法还有不少,但愿本文能提供给你们一些思路,后续会继续更新。


 

UPA—— 一款针对Unity游戏/产品的深度性能分析工具,由腾讯WeTest和unity官方共同研发打造,能够帮助游戏开发者快速定位性能问题。旨在为游戏开发者提供更完善的手游性能解决方案,同时与开发环节造成闭环,保障游戏品质。

 

 

目前,限时内测正在开放中,即日起至2017.12.21,全部预定成功的WeTest平台认证用户,都可以避免费、不限次数地使用最完整的UPA服务,点击http://wetest.qq.com/cube/ 当即预定。

对UPA感兴趣的开发者,欢迎加入QQ群:633065352

 

 

 

若是对使用当中有任何疑问,欢迎联系腾讯WeTest企业QQ:800024531

相关文章
相关标签/搜索