经验之道:最有效的 iOS 内存泄漏检测

作者:胡涛

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

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

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

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

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

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

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

  1. 首先,我先上图,看一下我的命名组织结构,遵循的就是模块化的命名,因为手Q的跨部门合作,所以用部门标记作为前缀。代码首先是要让人来看的,是人在维护程序,所以可读性非常重要,在开发完这些功能后,我对于所有对象在运行过程中的创建与销毁是很清楚的。
  2. 接下来我要进入instruments来进行内存测试,profile运行Leaks就OK了,就会进入下面看到的界面,详细讲解一下都是什么吧,这些对对象怎么分配内存的很重要。
  1. 然后我就需要操作模拟器来进入我所开发的功能模块,会看到非常复杂的对象分配情况,所以这一步非常关键,我只需要在搜索框搜索模块的前缀就可以只显示当前模块所涉及的对象分配与销毁情况,如下图,进入了的模块视图:
  2. 接下来我执行一个环境查询的命令,再看一下执行之后的内存分配情况。
  1. 我的逻辑是这样的,点击一次创建一个命令(VASDebugPlatformServerCmd),通过这个命令初始化并执行一个任务,任务结束后就销毁这个任务对象(VASDebugPlatformBaseOperation),相应的命令也作为任务的成员一起被销毁。所以,在动作执行完后我们应该可以在已销毁对象中找到这个实例,运行截图如下:
  2. 我看到任务是已经被销毁了的,可是用来初始化的命令对象为什么没有被销毁,我需要深挖一下这个命令对象(VASDebugPlatformServerCmd)的引用计数到底怎么发生变化的,就需要用到下面的步骤了,按照图解去深挖它:
  1. 我挖到命令对象的内部,一路挖到底,我发现命令对象最终的引用计数是1,证明它还在内存中活着,截图是这样的:
  2. 所以,我就看看,任务对象销毁了,那任务对象到底发生了什么事 截图是这样的:
  1. 我就是不死心,我就是要看到,到底是不是真的呢,为了进一步佐证命令对象在内存中,我在对象内部观察了一个内存检测的通知,收到通知后弹一个alert出来,如果对象被销毁了,它肯定收不到这个通知,如下面截图所示的工作:
  2. 因为这是我自己写的逻辑,我很清楚对象在哪里分配内存,然后我就去查代码,命令对象到底经历了什么,从开始到结束的执行过程是什么样的:
  1. 看完上面的截图,再去看命令对象的引用计数变化就知道为什么了:
  2. 当然,我也看出了为什么引用计数没有归零,所以,我在下面进行了修复:
  1. 再次profile->Leaks , 然后我再做一次查询任务,看看这次命令对象的引用计数变化,命令对象被释放了!:
    总结:
  2. 保持你的模块拥有一个良好的命名空间

  • 请深刻并且清楚的知道,触发什么事件,执行UI动作之后,你的对象分配会是什么样的,谁此刻应该存在内存中,谁应该被销毁,然后利用上面的原理去查看,它是不是被销毁了,如果没有被销毁,那么你应该去查你的代码,到底在执行过程中,哪里没有平衡引用计数。
  • 此方法在ARC和MRC的情况都是适用的,目标是观察具体哪个实例对象没有被销毁,然后根据引用计数变化跳转到代码中去确认哪里出现了内存问题。

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

相关推荐

App性能监控,拒绝用户流失

快速定位手游内存占用过高问题

原创声明,本文系作者授权云+社区发表,未经许可,不得转载。

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

编辑于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏coder修行路

python爬虫从入门到放弃(九)之 实例爬取上海高级人民法院网开庭公告数据

通过前面的文章已经学习了基本的爬虫知识,通过这个例子进行一下练习,毕竟前面文章的知识点只是一个 一个单独的散知识点,需要通过实际的例子进行融合 分析网站 其实爬...

1787
来自专栏XAI

【Python3-API】情感倾向分析示例代码

Python3-urllib3-API情感倾向分析示例代码 AccessToken获取可以参考:http://ai.baidu.com/forum/topic/...

2259
来自专栏前端黑板报

JavaScript模块探索

随着JS项目越来越大,再依靠简单的命名空间来解决冲突不是很可取,项目大了之后不只有变量冲突的问题,还有模块依赖以及加载策略的问题等,这次就介绍现存的几种模块化、...

1825
来自专栏贾鹏辉的技术专栏@CrazyCodeBoy

React Native 开发适配心得

众所周知用React Native是可以开发跨平台的Android和iOS App。我们可以用React Native开发Android应用也可以开发iOS应用...

3255
来自专栏java学习

Java每日一练(2017/7/3)

Java基础 | 数据库 | Android | 学习视频 | 学习资料下载 最新通知 ●回复"每日一练"获取以前的题目! ●【新】Ajax知识点视频更新了!(...

3307
来自专栏地方网络工作室的专栏

Vue2+VueRouter2+Webpack+Axios 构建项目实战2017重制版(九)再把内容页面渲染出来

Vue2+VueRouter2+Webpack+Axios 构建项目实战2017重制版(九)再把内容页面渲染出来 前情回顾 在上一篇博文《Vue2+VueRou...

20110
来自专栏不止是前端

Vue:基于Vue2的饿了么实战总结

3327
来自专栏深度学习那些事儿

理解matplotlib、pylab与pyplot之间的关系

这些模块其实功能都相同,程序运行的时候都在运行相同的code,不同的是导入模块的方式不同。

1714
来自专栏OY写东西的地方

使用Typescript给JavaScript做静态类型检查

笔者所说的这个项目,是一个运行了接近五年的老项目,代码横跨es3到es6。而且代码风格由于项目的人员流动也各异。由于项目人数越来越多,以前留下的技术债造成的危害...

590
来自专栏无原型不设计

怎样使用原型设计中的组件样式功能

“样式”是一个集中管理你整个项目的页面和部件的外观和感受的解决方案。可以把它理解为微软Office Word中的样式,或修饰HTML的CSS样式。

1.2K18

扫码关注云+社区