前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >实践-做一个会性能调优的好猿

实践-做一个会性能调优的好猿

作者头像
進无尽
发布2018-09-12 18:23:04
1K0
发布2018-09-12 18:23:04
举报
文章被收录于专栏:進无尽的文章進无尽的文章

前言

对于每位 iOS 开发者来说,代码性能是个避不开的话题。随着项目的扩大和功能的增多,没经过认真调试和优化的代码,要么任性地卡顿运行,要么低调地崩溃。一般性能测试都是从CPU、内存、响应时间(反应时间)来进行测试和以及后续优化的切入点。Xcode自帶的Instruments 提供了丰富的测试工程性能的工具,本文就为大家带来几个实用的工具使用。Apple关于Instuments的介绍

在做性能测试的时候我们需要注意几点:

  • 测量,而不是猜测

不光是性能优化,调Bug,修复崩溃等很多工作中,很多人凭借“经验”自信地改动代码以为就能完美解决发现的问题,往往是浪费了很多的时间或者创作出新的Bug或者问题。测量,而不是猜测,才是正确的姿势。

  • 真机测试,而不是模拟器

当你开始做一些性能方面的工作时候,一定要在真机上测试,而不是模拟器,模拟器运行在Mac上,然而Mac上的cpu比ios设备要快很多。另外 在使用 Core Animation 时,只有真机才可以测试,模拟器无法测试。

  • 如何使用 Instuments

连上真机,如下执行 Profile【快捷键 command+I 】即可

Paste_Image.png

选择某个测试工具界面如下:

Paste_Image.png

点击红色的按钮,会启动真机上的应用,运行应用即可,即可进入测试性能模式。

几个实用的测试工具
  • 静态性能检测 Analyze

Analyze主要分析以下四种问题: 1、逻辑错误:访问空指针或未初始化的变量、未使用的变量等; 2、内存管理错误:如内存泄漏等; 3、声明错误:从未使用过的变量; 4、Api调用错误:未包含使用的库和框架。 最简单、轻便的内存检测方式。

  • Allocations:监测内存使用 / 分配情况 迅速膨胀的内存可以很快让程序毙命,所以要多加防范。 管理内存是app开发中最重要的一个方面,对于开发者来说,在程序架构中减少内存的使用通常都是使用Allocations去定位和找出减少内存使用的方式,接下来谈一下内存泄漏的两种情况 第一种:为对象A申请了内存空间,之后再也没用过对象A,也没释放过A导致内存泄漏,这种是Leaked Memory内存泄漏。 第二种:类似于递归,不断地申请内存空间导致的内存泄漏,这种情况是Abandoned Momory此工具可以让开发者很好的了解每个方法占用内存的情况,并定位相关的代码

1483621770994991.png

右键就可以打开Xcode自动定位到相关占用内存方法的代码上

1483621806154847.png

第二种情况可以根据下图的操作清晰的找到对用的代码问题

1483621830325953.png

解释一下,第二种情况我们应该如何操作,重复的执行一系列的操作时候内存不会继续增加,比如打开和关闭一个窗口,这样的操作,每一次操作的前后,内存应该是相同的,通过多次循环操作,内存不会递增下去,通过这种分析结果,观察内存分配趋势,当发现不正确的结果或者矛盾的结果,就可以研究是不是Abandoned Momory的问题,并可以修正这个问题了。 </br> 我在测试一个地图相关的项目时,进入一个有地图的页面后,再次返回,激增的内存并没有降到原来的水平,于是看得出代码造成中没有释放地图的内存。

Paste_Image.png

代码语言:javascript
复制
#查阅资料了解到removeFromSuperview可以释放内存,并且需要把对象指针置空,这样对应的对象才会被释放,
#以下代码缺一不可。
- (void)viewWillDisappear:(BOOL)animated
{
    [super viewWillDisappear:YES];
    [myMapView removeFromSuperview];
    myMapView = nil;
    self.walkManager = nil;
 }

Paste_Image.png

  • Core Animation 理想的FPS值为60左右,过低的话就用该进性优化了,根据WWDC的说法,当FPS 低于45的时候,用户就会察觉到到滑动有卡顿

1483621877125562.png

圈着数字红色方框中的数字,代表着FPS值,理论上60最佳,实际过程中59就可以了,说明就是很流畅的,说明一下操作方式:在手指不离开屏幕的情况下,上下滑动屏幕列表介绍一下Deug Display中选项的作用 Color Blended Layers(混合过度绘制)

打开此选项屏幕的效果图如下:

1483621901286697.jpg

这个选项基于渲染程度对屏幕中的混合区域进行绿到红的高亮(也就是多个半透明图层的叠加),由于重绘的原因,混合对GPU性能会有影响,同时也是滑动或者动画掉帧的罪魁祸首之一GPU每一帧的绘制的像素有最大限制,这个情况下可以轻易绘制整个屏幕的像素,但如果发生重叠像素的关系需要不停的重绘同一区域的,掉帧和卡顿就有可能发生GPU会放弃绘制那些完全被其他图层遮挡的像素,但是要计算出一个图层是否被遮挡也是相当复杂并且会消耗CPU的资源,同样,合并不同图层的透明重叠元素消耗的资源也很大,所以,为了快速处理,一般不要使用透明图层,1). 给View添加一个固定、不透明的颜色2). 设置opaque 属性为true但是这对性能调优的帮助并不大,因为UIView的opaque 属性默认为true,也就是说,只要不是认为设置成透明,都不会出现图层混合而对于UIIimageView来说,不仅需要自身需要不是透明的,它的图片也不能含有alpha通道,这也上图9张图片是绿色的原因,因此图像自身的性质也可能会对结果有影响,所以你确定自己的代码没问题,还出现了混合图层可能就是图片的问题了而针对于屏幕中的文字高亮成红色,是因为一没有给文字的label增加不透明的背景颜色,而是当UILabel内容为中文时,label的实际渲染区域要大于label的size,因为外围有了一圈的阴影,才会出现图层混合我们需要给中文的label加上如下代码:

代码语言:javascript
复制
retweededTextLab?.layer.masksToBounds = true
retweededTextLab?.backgroundColor = UIColor.groupTableViewBackground
statusLab.layer.masksToBounds = true
statusLab.backgroundColor = UIColor.white

看下效果图:

1483621968537192.png

那些label的颜色也变成蓝色的了,这里有一点需要说明一下, (1). statusLab.layer.masksToBounds = true 单独使用不会出现离屏渲染 (2). 如果对label设置了圆角的话,圆角部分会离屏渲染,离屏渲染的前提是位图发生了形变

Color Hits Green and Misses Red(光栅化缓存图层的命中情况)

这个选项主要是检测我们有无滥用或正确使用layer的shouldRasterize属性.成功被缓存的layer会标注为绿色,没有成功缓存的会标注为红色。很多视图Layer由于Shadow、Mask和Gradient等原因渲染很高,因此UIKit提供了API用于缓存这些Layer,self.layer.shouldRasterize = true系统会将这些Layer缓存成Bitmap位图供渲染使用,如果失效时便丢弃这些Bitmap重新生成。图层Rasterization栅格化好处是对刷新率影响较小,坏处是删格化处理后的Bitmap缓存需要占用内存,而且当图层需要缩放时,要对删格化后的Bitmap做额外计算。 使用这个选项后时,如果Rasterized的Layer失效,便会标注为红色,如果有效标注为绿色。当测试的应用频繁闪现出红色标注图层时,表明对图层做的Rasterization作用不大。在测试的过程中,第一次加载时,开启光栅化的layer会显示为红色,这是很正常的,因为还没有缓存成功。但是如果在接下来的测试,。例如我们来回滚动TableView时,我们仍然发现有许多红色区域,那就需要谨慎对待了。

  • Leaks:找到引发内存泄漏的起点

一个灰常重要的工具,主要检查内存泄漏,在前面Allcations里面我们提到内存泄漏分两种,现在我们研究Leaked Memory, 从用户使用角度来看,内存泄漏本身不会产生什么危害,作为用户,根本感觉不到内存泄漏的存在,真正的危害在于内存泄漏的堆积,最终会耗尽系统所有的内存。我们直接看图:

1483622278645630.png

在 instruments 中,虽然选择了 Leaks 模板,但默认情况下也会添加 Allocations 模板.基本上凡是内存分析都会使用 Allocations 模板, 它可以监控内存分布情况。选中 Allocations 模板3区域会显示随着时间的变化内存使用的折线图,同时在4区域会显示内存使用的详细信息,以及对象分配情况.点击 Leaks 模板, 可以查看内存泄露情况。如果在3区域有 红X 出现, 则有内存泄露, 4区域则会显示泄露的对象.打用leaks进行监测:点击泄露对象可以在(下图)看到它们的内存地址, 占用字节, 所属框架和响应方法等信息.打开扩展视图, 可以看到右边的跟踪堆栈信息,4 黑色代码最有可能出现内存泄漏的方法。

1483622325201298.png

  • Time Profiler:分析代码的执行时间,找出导致程序变慢的原因。 右侧选项的意义

Separate by Thread: 按线程分开做分析,这样更容易揪出那些吃资源的问题线程。特别是对于主线程,它要处理和渲染所有的接口数据,一旦受到阻塞,程序必然卡顿或停止响应。 Invert Call Tree:反向输出调用树。把调用层级最深的方法显示在最上面,更容易找到最耗时的操作。 Hide Missing Symbols:隐藏缺失符号。如果 dSYM 文件或其他系统架构缺失,列表中会出现很多奇怪的十六进制的数值,用此选项把这些干扰元素屏蔽掉,让列表回归清爽。 Hide System Libraries:隐藏系统库文件。过滤掉各种系统调用,只显示自己的代码调用。 Flattern Recursion:拼合递归。将同一递归函数产生的多条堆栈(因为递归函数会调用自己)合并为一条。 Top Functions:找到最耗时的函数或方法。

在开发的过程中,我们经常能感觉到,点击某一按钮,或者做了某一操作,有卡顿,这就是延迟,那使用此工具,就可以揪出耗时的函数,先看一下,调试界面介绍:

1483622395450987.png

根据查看的相关耗时操作,我们就可以右键定位当耗时的方法: 下图是我的一个测量结果,可以看到有在主线程中有个耗时5S的操作,通过层层查找我们最后找到了这个耗时巨大的方法在 TwoViewContorller ViewDidLoad 中,右键 Reveal in Xcode 中我们可以看到,是我故意写的一个主线程中的for循环。

Paste_Image.png

代码语言:javascript
复制
- (void)viewDidLoad {
    [super viewDidLoad];
      #找到这个耗时巨大的方法所在
    for (int i = 0; i<50000; i++) {
       NSLog(@"YYYY" );
    }
 }
  • UIKit性能调优实战讲解: fps表示frames per second,也就是每秒钟显示多少帧画面。对于静止不变的内容,我们不需要考虑它的刷新率,但在执行动画或滑动时,fps的值直接反映出滑动的流畅程度. 个人认为比opaque属性更重要的是backgroundColor属性,如果不设置这个属性,控件依然被认为是透明的,所以我们做的第一个优化是 设置控件的背景颜色。
小结

APP性能调试在App的开发中是很重要的,后续有新的收获或者新的方法用到,会持续更新的。


本文参考文章 iOS 性能调优,成为一名合格iOS程序员必须掌握的技能

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2017.02.28 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • 在做性能测试的时候我们需要注意几点:
    • 几个实用的测试工具
      • 小结
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档