一、内存优化

简介:
Objective_C 有3种内存管理方法, 它们分别是

- MRR (Manual Retain Release, 手动保持释放)- ARC(Automatic Reference Counting, 自动引用计数)- GC(Garbage Collection, 垃圾收集)
  • 1>MRR
    ① 也称为 MRC(Manual Reference Counting, 手动引用计数)
    ② 由程序员自己负责管理对象生命周期,负责对象的创建和销毁.

  • 2>ARC
    ① 采用和 MRR 一样的内存引用计数管理方法。
    ② 在编译时会在适合的位置插入对象内存释放, (如 release, autorelease, 和 retain 等),
    ③ 程序员不用关心对象释放的问题, 苹果推荐在新项目中使用 ARC, 但在 iOS5之前的系统中不能采用 ARC.

  • 3>GC
    ① 在Objective_C2.0之后, 内存管理出现了类似于 Java 和 C#的内存垃圾收集技术, 但是垃圾收集与 ARC 一直运行, 垃圾收集是后台有一个线程负责检查已经不再使用的对象,然后释放之.
    ② 由于后台有一个线程一直运行, 一次会严重影响性能, 这也是 Java 和 C#程序的运行速度无法超越 C++的主要原因.
    ③ GC 技术不能应用于 iOS 开发, 只能应用于Mac OS X 开发.

    小结:
    从上面的介绍可知:

  • ① iOS 采用 MRR 和 ARC 这两种方式, ARC 是苹果推荐的方式.

  • ② MRR 方式相对比较原始, 对于程序员的能力要求很高, 但是它很灵活, 方便, 很不容易驾驭好.

二、内存泄露

1> 什莫是内存泄露?
  内存泄露指当一个对象或变量在使用完成后没有释放掉, 这个对象一直占用着这部分内存, 直到应用停止.

2> 这种没有 释放掉的对象 多了会发生什么呢?
  如果这种对象过多,内存就会耗尽,其他应用就无法运行.

3> 在哪里比较普遍?
这个问题在 C++, C 和 Objective-C的 MRR 中是比较普遍的问题.

4> 理论与实际?
  从理论上讲, 内存泄露是由对象或变量没有释放引起的, 但实践证明并非所有的未释放的对象或变量都会导致内存泄露, 这与硬件环境和操作系统系统环境有关。

5> 我们该怎么办呢?
  我们需要检测工具帮助我们找到这些"泄漏点".

6> 为什么要测试代码的内存泄露?
  内存的泄露导致我们软件在运行过程中占用越来越多的内存,占有资源却又得不到及时清理,会导致我们程序效率越来越低,反应慢,会影响我们用户体验,失去市场的竞争能力.

三、查找泄漏点 (两种工具)

在 Xcode 中, 共提供了两种工具帮助查找泄漏点

1 > Analyze

- 学 名:  静态分析工具- 查 找:  可以通过 Product ->Analyze 菜单项启动- 快捷键:  CMD+shift +b.- Analyze主要分析以下四种问题:
  1) 逻辑错误:访问空指针或未初始化的变量等;
  2) 内存管理错误:如内存泄漏等;
  3) 声明错误:从未使用过的变量;
  4) Api调用错误:未包含使用的库和框架。

2 >Instruments

- 学 名:   动态分析工具- 查 找:   Product ->Profile 菜单项启动- 快捷键:  CMD + i.- 简 介:它有很多跟踪模块可以动态分析和跟踪内存, CPU 和文件系统.

四、两种工具查找漏点版面的介绍

1 > 结合使用-思路分析:

  先使用 Analyze 静态分析查找可疑泄漏点, 再用Instruments动态分析中的 Leaks 和 Allocations 跟踪模板进行动态跟踪分析, 确认这些点是否泄漏, 或者是否有新的泄漏点出现等.

2 > 使用 静态检测内存泄漏工具 Analyze 
  在 Analyze 静态分析结果中, 凡是有图标

分析结果图标

出现的行都是工具发现的疑似泄露点.

疑似泄漏点所在行

点击疑似泄漏点行末尾的分叉图标,会展开分析结果:

展开分析结果

检测完成时的效果图如下

效果图

小结:
  这里使用 Analyze 静态分析查找出来的泄漏点,称之为"可疑泄漏点".之所以称之为"可疑泄漏点",是因为这些点未必一定泄露,确认这些点是否泄露, 还要通过 Instruments 动态分析工具的 Leaks 和 Allocations 跟踪模板. Analyze 静态分析只是一个理论上的预测过程.

3 > 动态监测Instruments的Leaks 
1) CMD + i 打开

打开

2) 打开界面的介绍:

界面的介绍

在 instruments 中,虽然选择了 Leaks 模板,但默认情况下也会添加 Allocations 模板.基本上凡是内存分析都会使用 Allocations 模板, 它可以监控内存分布情况。

  ① 选中 Allocations 模板,(图1区域),右边的3区域会显示随着时间的变化内存使用的折线图,同时在4区域会显示内存使用的详细信息,以及对象分配情况.

  ② 点击 Leaks 模板(图中2区域), 可以查看内存泄露情况。如果在3区域有 红X 出现, 则有内存泄露, 4区域则会显示泄露的对象.

3) 打用leaks进行监测:
  点击泄露对象可以在(下图)看到它们的内存地址, 占用字节, 所属框架和响应方法等信息.打开扩展视图, 可以看到右边的跟踪堆栈信息

leaks进行监测

4) 监测结果的分析:

监测结果的分析

4 > Allocations—内存分配版面的介绍 
Allocations是检测程序运行过程中的内存分配情况的,也需要同时运行着程序。界面情况如下:

Allocations

Allocations

双击某一个方法,同样会跳转到代码里,会有每一句代码对应的内存分配情况,根据这些信息,可以对程序里不同代码的内存占用情况有一些认识,并进行针对性的优化。

五、具体使用

1>.Allocations纪录了内存分配,用来优化内存使用的
2>.Leaks用来分析内存泄漏。ARC中引起的内存泄漏原因就是引用环。

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

泄漏了多少

第二步
然后看看Call Tree,因为Call Tree会给我们大概的位置,有时候会给我们精确的位置,不过要看运气了。
然后,再右面选择Invert Call Tree和Hide System Library

Call Tree

然后双击 上文图片中的任意一行,就会跳到代码处内存泄漏的地方(事实上,到这步,很多内存泄漏的问题都会被发现),当然也有一些泄露还是看不出来的.

第三步
  然后我们选择对ARC调试很有用的一个部分Circles & Roots,通过这个我们可以看到详细的ARC引用计数过程。然后,我们看到如下图

小的红色矩形点击可以看到引用计数的详细信息(ARC 就是自动引用计数,计数为0,则对象会被释放)

大的红色矩形可以绘制对象引用环的图,这里如果是我们自己的东西,就能看出来各个对象之间的引用.

  如果这里没有引用环的图. 首先我们找一下我们自定义的对象,正常完成任务这个对就应该释放的. 为了确认这个对象有没有释放, 可以重写 dealloc 方法, 在此方法中 log 释放信号, 看看是否被释放.

  如果这里就是没有释放,我们可以点击这儿对象后的箭头详细的看下, 这个对象的引用计数变化如图.

 - All 表示所有的引用计数变化
- Unpaired表示那些为成对的变化``(成对就是leaks识别出了对应的+,-)
- By Group会把相关的变化分成一组,
- ByTime会按照顺序列出引用计数变化

我们选择Unpaired 和 ByGroup,看到如图

按照顺序看(最左边的标号)
4 这里,引用计数是一,这是正确的,因为到这里正常就是应该是OperationQueue保存一个Operation的引用。 于是,我们把正常的划掉

再继续看,download start 标号6和8是对应的,继续排除问题出现在这里(当然问题不可能出现在这里,这是系统的API,一定会释放,就是简单教大家如何看)

再看看,+1的还剩下标号7 和 11,7 是正常的为Operation分配线程,应当会+1,而11就是我们的问题所在了(大部分Delegate都不会使引用+1)。 我们再看下文档

@property(readonly, retain) id< NSURLSessionDelegate > delegate

原来这个代理是retain啊,不是assign或者weak。所以形成了这样的引用环。

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

  + (NSURLSession *)sessionWithConfiguration:(NSURLSessionConfiguration *)configuration delegate:(id)delegate delegateQueue:(NSOperationQueue *)queue:

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

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

  •   -(void)setOperationFinished
    {
    [self.session invalidateAndCancel];
    }

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

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

建议:
  如果我们未发现表示内存泄露的红 X, 但是我们想进一步评估某个对象对于内存的应用, 可以看看 Allocations 模板的折线图. 反复执行从创建对象 -> 销毁对象 这个过程, 如果总占用内存数会随之增加, 这说明这个对象没有释放, 有些时候虽然占用的内存不是很严重, 但是也会增加占用内存, 因此必须释放这个对象.

  提示:有些情况下, 对象没有释放是无法检测到的,反复测试内存占用也没有明显的增加, 这时最好在配置比较低的设备上测试一下, 如果问题依然, 可以不用释放对象. 但是从编程习惯上讲, 我们应该释放该对象.

  事实上,内存泄露是及其复杂的问题, 工具使用是一方面, 经验是另一方面. 提高经验, 然后借助工具才能解决内存泄露的根本.

扩展小知识

1.什莫是内存溢出 out of memory ?
  是指程序在申请内存时,没有足够的内存空间供其使用,出现out of memory;比如申请了一个integer,但给它存了long才能存下的数,那就是内存溢出。

Instruments之Leaks学习的更多相关文章

  1. 使用Xcode和Instruments调试解决iOS内存泄露

    转载自:http://www.uml.org.cn/mobiledev/201212123.asp  (或者http://www.cocoachina.com/bbs/read.php?tid=129 ...

  2. 【转】使用Xcode和Instruments调试解决iOS内存泄露

    原文网址:http://blog.csdn.net/totogo2010/article/details/8233565 虽然iOS 5.0版本之后加入了ARC机制,由于相互引用关系比较复杂时,内存泄 ...

  3. Instruments --- 内存泄露

    虽然iOS 5.0版本之后加入了ARC机制,由于相互引用关系比较复杂时,内存泄露还是可能存在.所以了解原理很重要. 这里讲述在没有ARC的情况下,如何使用Instruments来查找程序中的内存泄露, ...

  4. [转]使用Xcode和Instruments调试解决iOS内存泄露

    虽然iOS 5.0版本之后加入了ARC机制,由于相互引用关系比较复杂时,内存泄露还是可能存在.所以了解原理很重要. 这里讲述在没有ARC的情况下,如何使用Instruments来查找程序中的内存泄露, ...

  5. 使用Xcode和Instruments调试解决iOS内存泄露【转】

    转载自:http://blog.csdn.net/totogo2010/article/details/8233565 虽然iOS 5.0版本之后加入了ARC机制,由于相互引用关系比较复杂时,内存泄露 ...

  6. 使用Xcode和Instruments调试解决iOS内存泄漏

    尽管iOS 5.0加入版本号之后ARC机制,由于相互引用关系是复杂的.内存泄漏可能仍然存在.于是,懂原理是非常重要的. 这里讲述在没有ARC的情况下,怎样使用Instruments来查找程序中的内存泄 ...

  7. ios Instruments 内存泄露

    本文转载至 http://my.oschina.net/sunqichao/blog?disp=2&p=3 虽然iOS 5.0版本之后加入了ARC机制,由于相互引用关系比较复杂时,内存泄露还是 ...

  8. 关于Instruments-Leaks工具的归纳总结

    前言: 本篇文章,在于学习,我把别人的一些感觉好的文章汇总成了一篇,亲自实现了一下,留用于今后学习资料. 文章脉络: 文章脉络: 一.内存优化 简介:Objective_C 有3种内存管理方法, 它们 ...

  9. xcode 手动管理内存 的相关知识点总结

    一.XCode4.2以后支持自动释放内存ARC xcode自4.2以后就支持自动释放内存了,但有时我们还是想手动管理内存,这如何处理呢. 很简单,想要取消自动释放,只要在  Build Setting ...

随机推荐

  1. Socket网络编程--聊天程序(7)

    接上一小节,本来是计划这一节用来讲数据库的增删改查,但是在实现的过程中,出现了一点小问题,也不是技术的问题,就是在字符界面上比较不好操作.比如要注册一个帐号,就需要弄个字符界面提示,然后输入数字表示选 ...

  2. oracle结合mybatis批量插入数据

    先上代码: controller: result = service.insertTRbXdhjLendYdData(params); service: List<TRbXdhjLendDTO& ...

  3. Android遍历API (1) 动画篇——克隆动画AnimationCloning

    从我学Android开始,一直就想做一件事.就是好好把APIDemo看一遍.今天开始会抽时间把Android官方的APIDemo程序全部过一遍.主要是为了两个目的:第一,复习以前学习的API用法.第二 ...

  4. java中的数据加密2 对称加密

    对称加密 也叫私钥加密.   采用单钥密码系统的加密方法,同一个密钥可以同时用作信息的加密和解密,这种加密方法称为对称加密,也称为单密钥加密. 需要对加密和解密使用相同密钥的加密算法.由于其速度快,对 ...

  5. 第三百九十二节,Django+Xadmin打造上线标准的在线教育平台—sql注入攻击,xss攻击,csrf攻击

    第三百九十二节,Django+Xadmin打造上线标准的在线教育平台—sql注入攻击,xss攻击,csrf攻击 sql注入攻击 也就是黑客通过表单提交的地方,在表单里输入了sql语句,就是通过SQL语 ...

  6. .Net Framework4.5.2 源码命名空间简析

    Miscosoft目前除.Net Core开源外,对于.Net4.5.1 , 4.5.2等后续版本同样开源.资源中包含sln,csproj等以方便我们在vs中打开它们,不过我们不能编译它,因为它缺少r ...

  7. 使用Android拨打电话功能

    1.要使用Android系统中的电话拨号功能,首先必须在AndroidManifest.xml功能清单中加入允许拨打电话的权限: <uses-permission android:name=&q ...

  8. PHP实现删除非站内外部链接实例代码

    /** *  删除非站内链接 * * @access    public * @param     string  $body  内容 * @param     array  $allow_urls  ...

  9. Android UI布局之RelativeLayout

    RelativeLayout是一个相对布局类. 首先RelativeLayout是一个容器,它里边的元素,如Buttonbutton等的位置是依照相对位置来计算的,比如,有两个Buttonbutton ...

  10. Hadoop -- ES -- CURD

    1.获取ES连接 package com.ciic.history.common; import org.elasticsearch.client.transport.TransportClient; ...