版权声明:本文由胡涛原创文章,转载请注明出处: 
文章原文链接:https://www.qcloud.com/community/article/125

来源:腾云阁 https://www.qcloud.com/community

使用instruments工具来更好的调试我们的工程中新开发或者修改过的模块的内存状况。

iOS设备性能越来越好,iOS App 也相应的变得越来越庞大,App代码的量级也在快速的增长,开发一个小的模块在工程中调试变的越来越难,通常我们是通过观察Allocation的内存变化高低,或者内存分配快照对比来寻找泄漏的情况,但这几乎是一个让人抓狂的调试方法,尤其在非常复杂的项目中,一个模块的推入与推出在Allocation上的变化微乎其微,而且受制于项目的复杂度,各种你所未知的对象的创建与销毁带来的Allocation图形高度的影响,对于观察Allocation的分配图像的高低变化来说,能够参考的意义就变的非常有限。

通过过去参与过的复杂大型的iOS项目开发经验,开发新的模块的时候,总结出了一套完整的iOS内存自测的方法,通过Instruments来逐步跟踪检测我们创建和主动销毁的对象是否真的销毁了。

在演示之前,需要强调一件事情就是,以文件夹目录作为你的空间命名很重要,请遵循开发新模块的时候使用你的模块的命名作为前缀。因为iOS没有命名空间这个东西,通常为了保证不冲突,我们都是以项目前缀+空间命名来保证文件的独立性,空间名就是目录和模块的名字了。这个在我们使用instruments进行内存检测的时候是非常重要的,接下来的使用过程就可以证实这一良好的命名习惯所带来的巨大好处,不只是优雅,更重要的是帮助。

除了命名,还有一件很重要的事情就是,你需要对你的模块在各种UI操作或者事件发生过程的情况下,对你的对象分配过程要非常非常清楚,因为这样,你才能看出相应的变化,哪些对象是应该存在的,哪些对象在某个动作结束后是必定会销毁的,这个应该很容易,你应该纯天然的就知道,因为你开发的整个逻辑。

最近在开发一个新的模块,正好需要在内存方面做一个完整的自测,既要确保效率,也要确保内存的正确分配与释放。

重要:(以下教程开始所有示例图片,请自行点击图片看大图,看的倍儿清楚!)

  1. 首先,我先上图,看一下我的命名组织结构,遵循的就是模块化的命名,因为手Q的跨部门合作,所以用部门标记作为前缀。代码首先是要让人来看的,是人在维护程序,所以可读性非常重要,在开发完这些功能后,我对于所有对象在运行过程中的创建与销毁是很清楚的。

  2. 接下来我要进入instruments来进行内存测试,profile运行Leaks就OK了,就会进入下面看到的界面,详细讲解一下都是什么吧,这些对对象怎么分配内存的很重要。

  3. 然后我就需要操作模拟器来进入我所开发的功能模块,会看到非常复杂的对象分配情况,所以这一步非常关键,我只需要在搜索框搜索模块的前缀就可以只显示当前模块所涉及的对象分配与销毁情况,如下图,进入了的模块视图:

  4. 接下来我执行一个环境查询的命令,再看一下执行之后的内存分配情况。

  5. 我的逻辑是这样的,点击一次创建一个命令(VASDebugPlatformServerCmd),通过这个命令初始化并执行一个任务,任务结束后就销毁这个任务对象(VASDebugPlatformBaseOperation),相应的命令也作为任务的成员一起被销毁。所以,在动作执行完后我们应该可以在已销毁对象中找到这个实例,运行截图如下:

  6. 我看到任务是已经被销毁了的,可是用来初始化的命令对象为什么没有被销毁,我需要深挖一下这个命令对象(VASDebugPlatformServerCmd)的引用计数到底怎么发生变化的,就需要用到下面的步骤了,按照图解去深挖它:

  7. 我挖到命令对象的内部,一路挖到底,我发现命令对象最终的引用计数是1,证明它还在内存中活着,截图是这样的:

  8. 所以,我就看看,任务对象销毁了,那任务对象到底发生了什么事 截图是这样的:

  9. 我就是不死心,我就是要看到,到底是不是真的呢,为了进一步佐证命令对象在内存中,我在对象内部观察了一个内存检测的通知,收到通知后弹一个alert出来,如果对象被销毁了,它肯定收不到这个通知,如下面截图所示的工作:

  10. 因为这是我自己写的逻辑,我很清楚对象在哪里分配内存,然后我就去查代码,命令对象到底经历了什么,从开始到结束的执行过程是什么样的:


  11. 看完上面的截图,再去看命令对象的引用计数变化就知道为什么了:
  12. 当然,我也看出了为什么引用计数没有归零,所以,我在下面进行了修复:
  13. 再次profile->Leaks , 然后我再做一次查询任务,看看这次命令对象的引用计数变化,命令对象被释放了!:

总结:

  • 保持你的模块拥有一个良好的命名空间

  • 请深刻并且清楚的知道,触发什么事件,执行UI动作之后,你的对象分配会是什么样的,谁此刻应该存在内存中,谁应该被销毁,然后利用上面的原理去查看,它是不是被销毁了,如果没有被销毁,那么你应该去查你的代码,到底在执行过程中,哪里没有平衡引用计数。

  • 此方法在ARC和MRC的情况都是适用的,目标是观察具体哪个实例对象没有被销毁,然后根据引用计数变化跳转到代码中去确认哪里出现了内存问题。

文章来源于公众号:小时光茶社(Tech Teahouse)

经验之道:最有效的iOS内存泄漏检测的更多相关文章

  1. 讲述Sagit.Framework解决:双向引用导致的IOS内存泄漏(下)- block中任性用self

    前言: 在处理完框架内存泄漏的问题后,见上篇:讲述Sagit.Framework解决:双向引用导致的IOS内存泄漏(中)- IOS不为人知的Bug 发现业务代码有一个地方的内存没释放,原因很也简单: ...

  2. iOS内存泄漏自动检测工具PLeakSniffer

    新款objective-C内存泄漏自动检测工具 PLeakSniffer , GitHub地址 (https://github.com/music4kid/PLeakSniffer). 背景 前些天读 ...

  3. 【YFMemoryLeakDetector】人人都能理解的 iOS 内存泄露检测工具类

    背景 即使到今天,iOS 应用的内存泄露检测,仍然是一个很重要的主题.我在一年前,项目中随手写过一个简单的工具类,当时的确解决了大问题.视图和控制器相关的内存泄露,几乎都不存在了.后来想着一直就那个工 ...

  4. 讲述Sagit.Framework解决:双向引用导致的IOS内存泄漏(中)- IOS不为人知的Bug

    前言: 话说昨晚还是前晚,写了一篇:讲述Sagit.Framework解决:双向引用导致的IOS内存泄漏(上) 文章写到最后时,多了很多莫名奇妙的问题!!! 为了解决了这些莫名奇妙的问题,我又战斗了2 ...

  5. iOS 内存泄漏监测自动化

    在 Android 上,Square 这家公司提供了非常有名的工具: leakcanary ,来帮助开发者们在日常开发过程中就能够发现内存泄漏.但在 iOS 上呢?在 Google 的时候,我发现了两 ...

  6. 精准 iOS 内存泄露检测工具

    MLeaksFinder:精准 iOS 内存泄露检测工具 发表于 2016-02-22   |   zepo   |   23 Comments 背景 平常我们都会用 Instrument 的 Lea ...

  7. Cocos开发中性能优化工具介绍之Visual Studio内存泄漏检测工具——Visual Leak Detector

    那么在Windows下有什么好的内存泄漏检测工具呢?微软提供Visual Studio开发工具本身没有什么太好的内存泄漏检测功能,我们可以使用第三方工具Visual Leak Detector(以下简 ...

  8. C/C++的内存泄漏检测工具Valgrind memcheck的使用经历

    Linux下的Valgrind真是利器啊(不知道Valgrind的请自觉查看参考文献(1)(2)),帮我找出了不少C++中的内存管理错误,前一阵子还在纠结为什么VS 2013下运行良好的程序到了Lin ...

  9. C++程序内存泄漏检测方法

    一.前言 在Linux平台上有valgrind可以非常方便的帮助我们定位内存泄漏,因为Linux在开发领域的使用场景大多是跑服务器,再加上它的开源属性,相对而言,处理问题容易形成“统一”的标准.而在W ...

随机推荐

  1. Window 2008 R2组策略之一——组策略管理控制台

    组策略管理在windows域管理中占有重要地位,本身也不是新的内容了.但微软在Windows2008中终于集成了一个非常好用的组策略管理工具——组策略管理控制台.并且为原有的组策略添加了新的元素.本文 ...

  2. CMake 使用方法

    CMake是一个跨平台的安装(编译)工具,可以用简单的语句来描述所有平台的安装(编译过程).他能够输出各种各样的makefile或者project文件,能测试编译器所支持的C++特性,类似UNIX下的 ...

  3. linux设置开机服务自动启动/关闭自动启动命令

    linux设置开机服务自动启动/关闭自动启动命令 2012-02-06 15:13 [root@localhost ~]# chkconfig --list     显示开机可以自动启动的服务[roo ...

  4. ES6 学习笔记 (2)-- Liunx环境安装Node.js 与 搭建 Node.js 开发环境

    笔记参考来源:廖雪峰老师的javascript全栈教程 一.安装Node.js 目前Node.js的最新版本是6.2.x.首先,从Node.js官网下载对应平台的安装程序. 1.下载 选择对应的Liu ...

  5. iOS边练边学--Segue数据逆传(用block代替delegate)

    一.block与方法的异同点: 相同点是都是保存代码段,什么时候执行,什么时候调用 不同点是block不受类或者对象的约束:方法收到了类或者对象的约束 二.思路:(通讯录练习) 在联系人控制器中,添加 ...

  6. golang中map并发读写问题及解决方法

    一.map并发读写问题 如果map由多协程同时读和写就会出现 fatal error:concurrent map read and map write的错误 如下代码很容易就出现map并发读写问题 ...

  7. 1​1​.​0​5​9​2​M​晶​振​与12M晶振

    标准的51单片机晶振是1.2M-12M,一般由于一个机器周期是12个时钟周期,所以先12M时,一个机器周期是1US,好计算,而且速度相对是最高的(当然现在也有更高频率的单片机). 11.0592M是因 ...

  8. NetBeans启动Tomcat报“'127.0.0.1' 不是内部或外部命令”启动失败的解决办法

    http://blog.sina.com.cn/s/blog_709548200102vgy4.html ——————————————————————————————————————————————— ...

  9. tab标签

    <ul class="nav nav-tabs" role="tablist" role="tablist" id="myT ...

  10. JavaScript初学者福利!必须收藏的24条小技巧

    JavaScript初学者福利!必须收藏的24条小技巧 前端小编 发布于 2013-12-15 22:52 查看数: 2343 评论数: 6 帖子模式 这篇文章将回顾JavaScript的知识 !如果 ...