项目的代码很多,前两天老大突然跟我说项目中某一个ViewController的dealloc()方法没有被调用,存在内存泄漏问题,需要排查原因,解决内存泄漏问题。由于刚加入项目组不久,对出问题的模块的代码还不太熟悉,所以刚拿到问题时觉得很棘手,再加上作为一个iOS菜鸟,对内存泄漏的排查方法和原因确实基本上不了解。所以,也借着这样的机会,我研究了一下关于iOS开发中内存泄漏的排查方法和原因分析。

  首先,补充两个基本概念的解释:

  • 内存溢出 (out of memory):是指程序在申请内存时,没有足够的内存空间供其使用,出现out of memory。通俗理解就是内存不够,通常在运行大型软件或游戏时,软件或游戏所需要的内存远远超出了你主机内安装的内存所承受大小,就叫内存溢出。
  • 内存泄露( memory leak):是指程序在申请内存后,无法释放已申请的内存空间,一次内存泄露危害可以忽略,但内存泄露堆积后果很严重,无论多少内存,迟早会被占光。

一、排查方法

  我们知道,iOS开发中对内存管理的要求非常严格,一旦存在内存泄漏,后果是非常严重的,会导致程序非常容易崩溃。尽管目前iOS开发基本上都是采用的ARC方式进行内存管理,但是一不小心就会存在内存泄漏的问题。

  首先,我们需要定位内存泄漏的问题,目前比较常用的内存泄漏的排查方法有两种,都在xcode中可以直接使用:静态分析方法(Analyze)和动态分析方法(Instrument的leak)。

1.1 静态内存泄漏分析方法

  通过xcode打开项目,然后点击product-->Analyze,如下图左侧的图所示,这样就开始对项目进行静态内存泄漏分析,分析结果如下图右侧的图所示。根据分析结果进行休整之后在进行分析就好了。

       

  静态分析方法能发现大部分的问题,但是只能是静态分析结果,有一些并不准确,还有一些动态分配内存的情形并没有进行分析。所以仅仅使用静态内存泄漏分析得到的结果并不是非常可靠,如果需要,我们需要将对项目进行更为完善的内存泄漏分析和排查。那就需要用到我们下面要介绍的动态内存泄漏分析方法Instruments中的Leaks方法进行排查。

1.2 动态内存泄漏分析方法

  分析内存泄露不能把所有的内存泄露查出来,有的内存泄露是在运行时,用户操作时才产生的。那就需要用到Instruments了。具体操作是通过xcode打开项目,然后点击product-->profile,如下图左侧图所示。

       

  按上面操作,build成功后跳出Instruments工具,如上图右侧图所示。选择Leaks选项,点击右下角的【choose】按钮,这时候项目程序也在模拟器或手机上运行起来了,在手机或模拟器上对程序进行操作,工具显示效果如下:

  点击左上角的红色圆点,这时项目开始启动了,由于leaks是动态监测,所以手动进行一系列操作,可检查项目中是否存在内存泄漏问题。如图所示,橙色矩形框中所示绿色为正常,如果出现如右侧红色矩形框中显示红色,则表示出现内存泄漏。

  选中Leaks Checks,在Details所在栏中选择CallTree,并且在右下角勾选Invert Call Tree 和Hide System Libraries,会发现显示若干行代码,双击即可跳转到出现内存泄漏的地方,修改即可。

二、内存泄漏的原因分析

  在目前主要以ARC进行内存管理的开发模式,导致内存泄漏的根本原因是代码中存在循环引用,从而导致一些内存无法释放,这就会导致dealloc()方法无法被调用。主要原因大概有一下几种类型。

2.1 ViewController中存在NSTimer

如果你的ViewController中有NSTimer,那么你就要注意了,因为当你调用

[NSTimer scheduledTimerWithTimeInterval:1.0
target:self
selector:@selector(updateTime:)
userInfo:nil
repeats:YES];
时的 target:self 就增加了ViewController的return count,如果你不将这个timer invalidate,将别想调用dealloc。

2.2 ViewController中的代理delegate

  一个比较隐秘的因素,你去找找与这个类有关的代理,有没有强引用属性?如果你这个VC需要外部传某个Delegate进来,来通过Delegate+protocol的方式传参数给其他对象,那么这个delegate一定不要强引用,尽量assign或者weak,否则你的VC会持续持有这个delegate,直到它自身被释放。

2.3 ViewController中Block

  这个可能就是经常容易犯的一个问题了,Block体内使用实例变量也会造成循环引用,使得拥有这个实例的对象不能释放。因为该block本来就是当前viewcontroller的一部分,现在盖子部门又强引用self,导致循环引用无法释放。 例如你这个类叫OneViewController,有个属性是NSString *name; 如果你在block体中使用了self.name,或者_name,那样子的话这个类就没法释放。 要解决这个问题其实很简单,就是在block之前申明当前的self引用为弱引用即可。

//MRC下代码如下
__block Viewcontroller *weakSelf = self;
//ARC下代码如下
__weak Viewcontroller *weakSelf = self;

2.4 ViewController的子视图对self的持有

这个问题也是我的项目中内存泄漏的问题所在。我们有时候需要在子视图或者某个cell中点击跳转等操作,需要在子视图或cell中持有当前的ViewController对象,这样跳转之后的back键才能直接返回该页面,同时也不销毁当前ViewController。此时,你就要注意在子视图或者cell中对当前页面的持有对象不能是强引用,尽量assign或者weak,否则会造成循环引用,内存无法释放。

iOS学习——内存泄漏检查及原因分析的更多相关文章

  1. 【c++】内存检查工具Valgrind介绍,安装及使用以及内存泄漏的常见原因

    转自:https://www.cnblogs.com/LyndonYoung/articles/5320277.html Valgrind是运行在Linux上一套基于仿真技术的程序调试和分析工具,它包 ...

  2. java内存泄漏的定位与分析

    1.为什么会发生内存泄漏 java 如何检测内在泄漏呢?我们需要一些工具进行检测,并发现内存泄漏问题,不然很容易发生down机问题. 编写java程序最为方便的地方就是我们不需要管理内存的分配和释放, ...

  3. (转)java内存泄漏的定位与分析

    转自:http://blog.csdn.net/x_i_y_u_e/article/details/51137492 1.为什么会发生内存泄漏 java 如何检测内在泄漏呢?我们需要一些工具进行检测, ...

  4. Windows平台上C++开发内存泄漏检查方法

    充分的利用调试工具可以非常方便地避免内存泄漏问题. 这里介绍两种方法,互为补充,第一种是VC编译器提供的方法,第二种是专用的内存泄漏检查工具Memmory Validator.这两种方法的基本原理是一 ...

  5. Java中关于内存泄漏出现的原因以及如何避免内存泄漏

    转账自:http://blog.csdn.net/wtt945482445/article/details/52483944 Java 内存分配策略 Java 程序运行时的内存分配策略有三种,分别是静 ...

  6. iOS AFNetworking内存泄漏处理方法

    iOS AFN内存泄漏处理方法 细心的你是否也发现AFN的内存泄漏的问题了呢. 在这里给大家提供一个解决AFN内存泄漏的方法. 单例解决AFN内存泄漏 + (AFHTTPSessionManager ...

  7. iOS常见内存泄漏解决

    iOS常见内存泄漏解决     1 OC和CF转化出现的内存警告 CFStringRef cfString = CFURLCreateStringByAddingPercentEscapes(kCFA ...

  8. c# 内存泄漏检查心得

    系统环境 windows 7 x64 检查工具:ANTS Memory Profiler 7 或者 .NET Memory Profiler 4.0 开发的软件为winform / windows s ...

  9. iOS 出现内存泄漏的几种原因

    一.从AFNet 对于iOS开发者,网络请求类AFNetWorking是再熟悉不过了,对于AFNetWorking的使用我们通常会对通用参数.网址环境切换.网络状态监测.请求错误信息等进行封装.在封装 ...

随机推荐

  1. linux使用yum安装mariadb

    一,安装 yum install mariadb mariadb-server 二,如何设置密码 用root 进入mysql后  mysql>set password =password('你的 ...

  2. Python 运行效率为何低

    当我们提到一门编程语言的效率时:通常有两层意思,第一是开发效率,这是对程序员而言,完成编码所需要的时间:另一个是运行效率,这是对计算机而言,完成计算任务所需要的时间.编码效率和运行效率往往是鱼与熊掌的 ...

  3. [Machine Learning]学习笔记-线性回归

    模型 假定有i组输入输出数据.输入变量可以用\(x^i\)表示,输出变量可以用\(y^i\)表示,一对\(\{x^i,y^i\}\)名为训练样本(training example),它们的集合则名为训 ...

  4. Innodb中的锁

    Innodb中的锁 共享锁和排它锁(Shared and Exclusive Locks)共享锁和排它锁是行级锁,有两种类型的行级锁 共享锁(s lock)允许持有锁的事务对行进行读取操作 排它锁(x ...

  5. 用swoole和websocket开发简单聊天室

    首先,我想说下写代码的一些习惯,第一,任何可配置的参数或变量都要写到一个config文件中.第二,代码中一定要有日志记录和完善的报错并记录报错.言归正传,swoole应该是每个phper必须要了解的, ...

  6. SEO是件贼有意思的事情 golang入坑系列

    这两天迷上了SEO.真心看不起百度的竞价排名,但作为一个商业网站,赚钱是一件无可厚非的事情.只做活雷锋,没有大金主是做不长的.做完功课后,发现百度和google的SEO策略又不相同,几乎是无法通用.百 ...

  7. php+jQuery+Mysql找回密码----ThinkPHP

    最近用ThinkPHP做了一个邮箱找回密码功能,在遭遇了N个bug之后终于做成了,下面分享一下邮箱找回密码功能的实现: 邮箱找回密码实际上就是在用户通过验证之后重置密码的过程,一般开发者会在验证用户信 ...

  8. css的padding和border问题

    第一步:先跟据需求定义一个div,要求width为300px,height为300px: 第二步:给该div添加一个边框,要求实线,宽度10px,粉色: 第三步:给该div再设置20px的内边距: 我 ...

  9. TensorFlow MNIST(手写识别 softmax)实例运行

    TensorFlow MNIST(手写识别 softmax)实例运行 首先要有编译环境,并且已经正确的编译安装,关于环境配置参考:http://www.cnblogs.com/dyufei/p/802 ...

  10. dock使用方法

    Docker 是一个开源项目,为开发者和系统管理员提供了一个开放的平台,在任何地方通过打包和运行应用程序作为一个轻量级的容器.Docker 在软件容器内自动部署应用程序.Docker 最开始由 Sol ...