总结:

三类工具

  • 基础工具 (NSLog的方式记录运行时间.)
  • 性能工具.检测各个部分的性能表现,找出性能瓶颈
  • 内存工具.检查内存正确性和内存使用效率

性能工具:

可以衡量CPU的使用,时间的消耗,电池的消耗

一、Time Profile

启动Time Profile:Xcode ——> Product ——> Profile ——> Time Profile

使用Time Profiler调试程序,能获取到整个应用程序运行中所消耗的时间分布和百分比

使用Time Profile前有两点需要注意的地方:

1、一定要使用真机调试

在开始进行应用程序性能分析的时候,一定要使用真机。因为模拟器运行在Mac上,然而Mac上的CPU往往比iOS设备要快。相反,Mac上的GPU和iOS设备的完全不一样,模拟器不得已要在软件层面(CPU)模拟设备的GPU,这意味着GPU相关的操作在模拟器上运行的更慢,尤其是使用CAEAGLLayer来写一些OpenGL的代码时候,这就导致模拟器性能数据和用户真机使用性能数据相去甚远

2、应用程序一定要使用发布配置

在发布环境打包的时候,编译器会引入一系列提高性能的优化,例如去掉调试符号或者移除并重新组织代码。另iOS引入一种"Watch Dog"[看门狗]机制,不同的场景下,“看门狗”会监测应用的性能,如果超出了该场景所规定的运行时间,“看门狗”就会强制终结这个应用的进程。开发者可以crashlog看到对应的日志,但Xcode在调试配置下会禁用"Watch Dog"

启动后如图

点击左上角红色按钮,开始调试

调试时注意右下方选项

Separate by Thread:每个线程应该分开考虑,只有这样你才能揪出那些大量占用CPU的"重"线程

Invert Call Tree:从上倒下跟踪堆栈,这意味着你看到的表中的方法,将已从第0帧开始取样,这通常你是想要的,只有这样你才能看到CPU中话费时间最深的方法,也就是说FuncA{FunB{FunC}} 勾选此项后堆栈以C->B-A 把调用层级最深的C显示在最外面

Hide System Libraries:勾选此项你会显示你app的代码,这是非常有用的。因为通常你只关心cpu花在你自己写的代码上的时间 而不是花在系统代码上的时间

Flatten Recursion:递归函数, 每个堆栈跟踪一个条目

Top Functions:一个函数花费的时间直接在该函数中的总和,以及在函数调用该函数所花费的时间的总时间。因此,如果函数A调用B,那么A的时间报告在A花费的时间加上B花费的时间,这非常有用,因为它可以让你每次下到调用堆栈时挑最大的时间数字,归零在你最耗时的方法

最终调试界面如图

双击选中行查看代码

发现循环中的UIImage *image = [UIImage imageNamed:imageName];语句的时间消耗最长,度娘之:

UIImage初始化方法有两种

A:imagedNamed初始化

B:imageWithContentsOfFile初始化

二者不同之处在于,imageNamed默认加载图片成功后会内存中缓存图片,这个方法用一个指定的名字在系统缓存中查找并返回一个图片对象,如果缓存中没有找到相应的图片对象,则从指定地方加载图片然后缓存对象,并返回这个图片对象

而imageWithContentsOfFile则仅只加载图片,不缓存

大量使用imageNamed方式会在不需要缓存的地方额外增加开销CPU的时间来做这件事,当应用程序需要加载一张比较大的图片并且使用一次性,那么其实是没有必要去缓存这个图片的,用imageWithContentsOfFile是最为经济的方式,这样不会因为UIImage元素较多情况下,CPU会被逐个分散在不必要缓存上浪费过多时间

使用场景需要编程时,应该根据实际应用场景加以区分,UIimage虽小,但使用元素较多问题会有所凸显

内存工具:

关心内存泄露和内存垃圾问题

一、Analyze静态分析

一. 静态内存分析

  1. 所谓静态内存分析, 是指在程序没运行的时候, 通过工具对代码直接进行分析

    • 根据代码的上下文的语法结构, 让编译器分析内存情况, 检查是否有内存泄露
  2. 作用

    • 逻辑错误: 访问未初始化的变量或者野指针
    • 声明错误: 声明了一个对象, 但是从未使用过
    • 内存管理错误: 内存泄露
    • 缺点: 静态内存分析由于是编译器根据代码进行的判断, 做出的判断不一定会准确, 因此如果遇到提示, 应该去结合代码上文检查一下
  3. OC中的静态内存分析:

    • 曾经在MRC环境下, OC的代码需要手动管理内存, 任何对象的引用, 都要伴随一次release操作, 否则很容易发生内存泄露, 因此在MRC环境下, 使用静态内存分析很有必要
    • 而在目前的ARC环境下, 很少会发生内存泄露, 但是也会有很少数的情况导致内存泄露
      • 如Foundation对象与CoreFoundation对象的相互转化, CoreFoundation对象享用ARC机制, 所以容易发生内存泄露
  4. Swift的静态内存分析

    • Swift中, 使用了类型重映射机制, 他可以将对象转换成能够自动管理内存的对象, 不需要我们手动释放, 因此Swift在内存管理方面更为安全

二. 内存分配

  1. 作用

    • 查看当前运行情况的内存分配
    • 查看使用过的内存有没有释放掉
  2. 关于App中加载图片的注意点

    • -imageNamed:

      • 该方法用于加载小图片/使用频率高的图片
      • 此方法加载过得图片, 在App运行期间, 始终会保有缓存, 这个缓存是由系统管理的, 无法通过代码销毁缓存
      • 当系统察觉到内存消耗过高, 就会自动释放这部分内存

          Search for an object whose name was set explicitly using the setName: method and currently resides in the image cache.
        该方法首先会从图片内存中查找
        Search the app's main bundle for a file whose name matches the specified string.
        如果没有找到, 就在App的mainBundle中查找
        Search the Application Kit framework for a shared image with the specified name.
        如果bundle中也没有, 就会去framework的库中寻找
    • -imageWithContentsOfFile:

      • 该方法用于加载大图片/使用率较低的图片
      • 它只是加载一次图片, 并且不会做缓存, 当对象释放的时候, 内存也就被释放掉了
      • 因此对于不常用的图片应该使用这个方法
  3. 图片在沙盒中的存在形式

    1. 如果当前项目部署版本 <= 6.x: 那么所有图片就会直接暴露在沙盒的资源包中(main bundle), 不会进行压缩为Assets.car文件
    2. 如果当前项目部署版本 >= 7.x
      • 放在Images.xcassets中的所有图片, 都会被压缩为Assets.car文件, 不会直接暴露在沙盒的资源包中
      • 而没有放在Images.xcassets的图片, 会直接暴露在沙盒的资源包中
    3. 使用对比
      • 压缩为Assets.car的文件:

        • 这些图片不会暴露在外, 但是无法或得到这些图片的路径, 只能通过图片名-imageName来加载图片, 并且会产生缓存
        • 小图片/使用频率高, 放在image.xcassets中
      • 未压缩的图片:
        • 图片暴露在外, 可以通过imageWithContentOfFile来获得图片的路径, 不会有缓存
        • 大图片/使用频率低, 如新特性界面, 放在外面

二、Leaks动态内存分析

对于有些内存泄漏情况通过静态分析无法解决的,可以通过动态分析来发现,分析起来更有针对性

点击XCode的Product菜单Profile启动Instruments:

选择Leaks,会自动启动Leaks工具和IOS模拟器:

Leaks启动后会开始录制,随着对模拟器运行的App的操作,可以在Leaks中查看内存占用的情况。

Leaks顶部分为两栏:Allocations和Leaks

Allocations纪录了内存分配,用来优化内存使用的

Leaks用来分析内存泄漏。ARC中引起的内存泄漏原因就是引用环。

看下效果图

 

乍一看还不错啊,tableview非常流畅,图片能够惰性下载(cell屏幕上再下载),这也是我想要的雏形。可是,好奇的用leaks分析一下

 

我擦

 然后,我们打开leaks,看看错误出现在哪

先选择Leaks和Leaks by Backtrace.这里可以看到那些对象内存泄漏了,泄漏了多少,这个就是简单看看,没有太多调试意义。

 

然后看看Call Tree,因为Call Tree会给我们大概的位置,有时候会给我们精确的位置,不过要看运气了。

 

然后,再又面选择Invert Call Tree和Hide System Library

 

然后,我们就知道大概内存泄漏的位置在NSOperation的子类这里了。

然后双击上文图片中的任意一行,就会跳到代码处内存泄漏的地方(事实上,到这步,很多内存泄漏的问题都会被发现)

那么怎么办呢?有问题下看文档,我们看到图片中引起引用计数加一的是

+ (NSURLSession*)sessionWithConfiguration:(NSURLSessionConfiguration*)configurationdelegate:(id)delegatedelegateQueue:(NSOperationQueue*)queue:

看下文档,发现了这个地方

 

于是,我们要手动的去断开强引用,于是,我们手动去断开

-(void)setOperationFinished{

[self.sessioninvalidateAndCancel];

[selfwillChangeValueForKey:@"isFinished"];

[selfwillChangeValueForKey:@"isExecuting"];

executing =NO;    finished =YES;

[selfdidChangeValueForKey:@"isExecuting"];

[selfdidChangeValueForKey:@"isFinished"];

}

再运行下看看,能够正常的Dealloc了

2015-06-0510:28:36.814AsyncImageTableviewDemo[1245:83664]dealloc2015-06-0510:28:36.954AsyncImageTableviewDemo[1245:83664]dealloc

用leaks分析,也没有内存泄漏了

 

总结:其实大多数问题在双击上文的代码部分就可以解决了,少数问题需要详细的分析ARC引用过程

三、Zombie内存垃圾

程序挂了的问题比性能问题严重得多.
可以在Instrument中开Zombie功能,使得内存crash的时候,能看到crash在哪个对象上.
还是那几个优缺点
这个东西一般在接到 EXEC_BAD_ACCESS的时候用.这个时候是内存访问的问题.

转自:https://www.cnblogs.com/junhuawang/p/5652996.html

最新文章

  1. 【IIS】iis6.1下添加两个ftp站点,
  2. mySql中alter table的使用
  3. 使用WindowsPE破解管理员密码
  4. sax 解析 xml
  5. 深入理解javascript中执行环境(作用域)与作用域链
  6. ajax获取数据库中数据
  7. USB2.0规范
  8. D3D11 Query查询耗时
  9. Android下载速度计算
  10. oracle新建用户
  11. Ubuntu 13.04 小米2S连接Eclipse真机调试
  12. Three.js 学习笔记(1)--坐标体系和旋转
  13. [bilibili]弹幕屏蔽列表
  14. Linux之DHCP搭建命令集锦
  15. IDEA编译时出现 Information:java: javacTask: 源发行版 1.8 需要目标发行版 1.8
  16. 关于docker 意外停止,重新快速启动措施
  17. ubuntu安装git
  18. Java开发万年历
  19. C#程序中判断DEBUG和RELEASE状态
  20. 禁用Visual Studio 2013的Browser Link功能 -调试不断请求http://localhost:6154/c4ad1c693ebf428283832eaa827f9c6e/arterySignalR/poll?transport=longPolling...

热门文章

  1. MyBatis(7)高级查询
  2. Redis的Windows端开发连接Linux端以及相应的代码实现
  3. 理解JavaScript执行环境与作用域
  4. Redis(RedisTemplate)使用hash哈希
  5. 利用来JS控制页面控件显示和隐藏有两种方法
  6. 关于sharepoint如何做SSO,如何做OOS监视编辑
  7. 手写redis客户端
  8. 并发之AtomicIntegerFieldUpdater
  9. 【补】英语对IT工作者的重要性
  10.  linux命令sed与awk是干什么用的,怎么用?