xcode里面使用Memory Leaks和Instruments检测内存泄漏
教程截图:

作为一名无证程序员,无论你多么精通Objective-C的内存管理,随着时间的推移,你也不可避免的犯内存相关的错误。但通常因为代码量太大,以至于你不可能一行一行的去排除(等你解决完,你设计的动车早相撞了!)
幸运的是,苹果已经提供了一些好的方式来帮助你找到应用程序中内存相关的问题。有时,这些工具可能吓到初学者,但它们实际上相当有用并易于掌握!
这就是本教程说要介绍的.你会亲手使用内存工具在XCode环境下很轻松的检测内存问题。
这篇教程是建立在你非常熟悉Objective-C内存管理的基础上。如果你还在这个问题上找不着北,你可能需要学习内存管理其他教程。
第一步
在这一节中,我们的目的是在一个例子应用程序中检查、解决任何内存泄漏问题,以演示常见的内存相关错误处理。开始,下载一个应用程序示例。我已经将教程和示例工程文件放在一起了。
在XCode中打开工程并运行。你会看到tableview中包含了一个寿司列表。试着选择几行,然后——轰!你看到可怕的EXC_BAD_ACCESS错误,编译器拿它完全没有办法。

因为xcode完全没指出出问题的地方,所以这种情况通常令许多开发者感到郁闷。当你遇到了一个EXC_BAD_ACCESS错误,我通常会给开发者几个建议:
1.在可执行选项中设置NSZombieEnabled参数,这有时会帮缩小问题的范围;
2.运行apple的内存检测工具,如 Leaks ,以便寻找内存问题;
3设定一个断点,单步运行代码,直到你找到引起崩溃的位置;
4.注释代码,直到不崩溃为止,然后再从后往前查找错误;
现在让我们从第一条开始实验
# 1 - NSZombieEnabled参数
一大波僵尸正在靠近!!!!
不幸的是,NSZombieEnabled选项对于崩溃毫无办法,所以你完全可以放弃抵抗。

当你试图使用一个已经被销毁的对象,NSZombieEnabled会标志一个警告,所以NSZombieEnabled只是一个flag。这是一个良好的开端,因为大多数崩溃的原因都是使用了已经销毁的对象。
按照以下设置:在XCode中展开Executables->双击PropMemFun->选择Arguments选项卡->“Variables to be set in the environment”点击加号按钮。把变量名值设置成NSZombieEnabled,把值设置成YES,如下图:(xcode4在左上角,edit schema里面)

重新运行app,随便操作下使程序崩溃。查看下console log你就会看到如下信息:
2011-02-0312:07:44.778 PropMemFun[27224:207] *** -[CFString respondsToSelector:]: message sent to deallocated instance ...
这个程序将在很精确的一行暂停。崩溃后,你可以通过选定第一个区域,回溯找出导致崩溃的准确行数。比如现在这个示例就崩溃在:tableView:didSelectRowAtIndexPath。

不管你信不信,反正找出了出问题的那行。导致崩溃的问题就是向已经销毁的string发送了一个消息。这一行用了两个string:_lastSushiSelected和sushiString.
因为这个string是由stringWithFormat初始化,所以看起来程序是没有问题了,因为stringWithFormat的返回值是自动释放的,所以在下次使用前应该是安全的。但是 _lastSushiSelected的安全性如何呢?
虽然_lastSushiSelected是在sushiString执行到最后才赋值的。但是sushiString是自动释放的,所以有些时候sushiString被释放了,内存也被销毁。但是紧接着_lastSushiSelected 仍然有可能指向被销毁的内存!这就解释了崩溃原因:向已经销毁的内存发送消息导致崩溃。
我们只需保留_lastSushiSelected就可以解决这个问题,把最后一行改成下面的样子:
_lastSushiSelected = [sushiString retain];
再次运行程序,你会发现程序已经畅通无阻了。
编译,分析和总结
至少,我们有一个不崩溃的应用程序——这是一个好的开始。但接下来,我们需要开始确保没有任何内存泄漏。
有一种简单的方法可以初步确认你的程序在初始化中是否有任何内存泄漏或其他问题--使用内置编译和分析功能(built-in Build and Analyze)。
这将使XCode执行你的代码和自动检测任何错误并警告你任何潜在的问题。它并不会找出所有的问题,但用这个方法找出的错误无疑是一个既快速又简单的方法。
试一试通过选择Build\Build and Analyze。你应该看到,它检测到一个内存泄漏,你可以看到如下:

消息显示,“alertView”有一个潜在的内存泄漏。如果你看看这一行,你就会发现所有的UIAlertView创造是有着alloc /init (返回一个对象引用数1),却从来没有真正地释放!有几种方法可以解决这个问题,但其中一个方法就是在[alertView show]下面加上一行:
[alertView release];
再次 Build\Build and Analyze,你会发现已经找不出任何内存问题了。
泄漏和管道
不幸的是,你不能依靠Build\Build and Analyze找出一切问题。有一个强大的自动化工具来帮助你检查程序是否有内存泄漏– the Leaks Instrument。
让我们试试看。选择Run\Run -> Performance -> Tool\Leaks,再选择table view中的几行。也可以上下滚动table view,从table view顶端到底部。基于前面的经验,你就应该开始看出一些蓝色的标签出现在泄漏的内存上。
点击停止按钮,然后去工具栏中点击“Leaked Blocks”让他变成“Call Tree”。在面板左下角,点击“Invert Call Tree”、“Hide System Libraries”。你将会看到这个工具发现两个不同的函数存在内存泄漏,你可以看到如下:

如果你双击一个函数的名字,它会带你直接到存在内存泄露的这行代码。这可以给你一个很好的错误位置提示,如果你查看代码并加以思考,你应该能够找出问题所在并解决它。
所以,为什么不看看代码,并且看看你是否能找出问题所在并修正吗?一旦你作出修改,并且能够无错误提示的跑Leaks。如果通过,表示你完成了
…
…waiting…
…
…waiitng…
…
…waiting…
…!

你已经搞定了,不管你信不信,反正我是信了。
解释一下
tableView:didSelectRowAtIndexPath
Leaks 告诉我们,这个问题的原因是字符串sushiString创造和存储过程中引起的内存泄漏。所以让我们一步一步的分析一下原因:
1.当sushiString被创建时,调用stringWithFormat。返回一个对象数值1并且发送autorelease消息。
2.在方法的最后一行,你在sushiString加入retain(retain数值增加到2)并将其存储到_lastSushiSelected。
3.后来,autorelease生效,retain数递减为1。
4.下一个tableView:didSelectRowAtIndexPath方法被调用,你重写_lastSushiSelected变量的一个指针指向一个新的字符串,- - - - -如果没有释放旧的! 所以那个老字符串并没有被释放仍然存在。
一个解决办法是增加下面一行在初始化lastSushiSelected sushiString之前:
[_lastSushiSelected release];
tableView:cellForRowAtIndexPath
就像在前面的方法,创建和存入名为sushiString的变量引起内存泄漏。以下是引起问题的分析:
1.一个新的字符串被alloc/init方法创建。
2.返回一个对象引用数 1.
3.然而,这个计数从来不减少,所以有一个内存泄漏!
这可以通过三种方式中的一种解决:
1.设置textLable为一个字符串后在sushiString中调用release方法。
2.alloc/init方法初始化完毕后在sushiString中调用autorelease。
3.用stringWithFormat代替alloc/init方法,返回一个已经标志为自动释放的字符串。
验证 leaks!
修正前面提到的问题,再次运行leaks,你会得到一个没有任何内存泄漏的app。
接下来该干什么?
这个链接可以下载到一个已经解决上述问题的工程文件。
最重要的是,你必须亲自实践使用NSZombieEnabled,Build and Analyze,和Leaks Instrument工具来找到内存泄漏。你应该能够很快把这项技术运用到你的工程中。
如果你有更好的方法,可以在下面评论,我也积极采纳大家的建议。
xcode里面使用Memory Leaks和Instruments检测内存泄漏的更多相关文章
- 使用Visual Leak Detector检测内存泄漏[转]
1.初识Visual Leak Detector 灵活自由是C/C++语言的一大特色,而这也为C/C++程序员出了一个难题.当程序越来越复杂时,内存的管理也会变得越加复杂,稍有不慎就会出现内存问题 ...
- IOS性能调优系列:使用Instruments动态分析内存泄漏
硬广:<IOS性能调优系列>第二篇,持续更新,欢迎关注. 第一篇介绍了Analyze对App做静态分析,可以发现应用中的内存泄漏问题,对于有些内存泄漏情况通过静态分析无法解决的,可以通过动 ...
- VC使用CRT调试功能来检测内存泄漏
信息来源:csdn C/C++ 编程语言的最强大功能之一便是其动态分配和释放内存,但是中国有句古话:“最大的长处也可能成为最大的弱点”,那么 C/C++ 应用程序正好印证了这句话.在 C/C+ ...
- Vc 检测内存泄漏
启用内存泄漏检测 检测内存泄漏是 C/c + + 调试器和 C 运行时库 (CRT) 的主要工具调试堆函数. 若要启用调试堆的所有函数,在 c + + 程序中,按以下顺序包含以下语句: C++复制 # ...
- 面向开发的内存调试神器,如何使用ASAN检测内存泄漏、堆栈溢出等问题
GreatSQL社区原创内容未经授权不得随意使用,转载请联系小编并注明来源. 目录 介绍 如何使用 ASAN 检测内存泄漏 检测悬空指针访问 检测堆溢出 C++ 中的new/delete不匹配 检测栈 ...
- Qt creator 搭配 valgrind 检测内存泄漏
继上次重载operator new检测内存泄漏失败之后,妥协了.决定不管是否是准确指明哪一行代码出现内存泄漏,只要告诉我是否有泄漏就行了,这样就没有new替换的问题.在开发中,总是一个个小功能的开发. ...
- Android性能优化之利用LeakCanary检测内存泄漏及解决办法
前言: 最近公司C轮融资成功了,移动团队准备扩大一下,需要招聘Android开发工程师,陆陆续续面试了几位Android应聘者,面试过程中聊到性能优化中如何避免内存泄漏问题时,很少有人全面的回答上来. ...
- 使用Memory Analyzer tool(MAT)分析内存泄漏(二)
转载自:http://www.blogjava.net/rosen/archive/2010/06/13/323522.html 前言的前言 写blog就是好,在大前提下可以想说什么写什么,不像投稿那 ...
- 使用Memory Analyzer tool(MAT)分析内存泄漏
前言的前言 写blog就是好,在大前提下可以想说什么写什么,不像投稿那么字字斟酌.上周末回了趟成都办事,所以本文来迟了.K117从达州经由达成线往成都方向走的时候,发现铁路边有条河,尽管我现在也不知道 ...
随机推荐
- leetcode 174. 地下城游戏 解题报告
leetcode 174. 地下城游戏 一些恶魔抓住了公主(P)并将她关在了地下城的右下角.地下城是由 M x N 个房间组成的二维网格.我们英勇的骑士(K)最初被安置在左上角的房间里,他必须穿过地下 ...
- 一个符号冲突导致的core分析
问题描述: 修改跟踪程序(Trace)支持IPV6时,发现程序启动后正常,但是客户端一旦下发查询条件进行跟踪,Trace程序就直接coredump! (gdb) bt # 0x00007f7dab9e ...
- Fomo3D代码分析以及漏洞攻击演示
Fomo3D过去的一周内赚足了噱头,一场光明正大的"庞氏"游戏疯狂吸金,在链得得此前的报道中提到"Fomo3D的开发者,是对生态有深刻理解的现实主义者.Fomo3D鼓励黑 ...
- c++ devived object model
单一虚函数继承 class A{public: virtual int foo( ) { return val ; } virtual int funA( ) {}private: int val ; ...
- Java设计模式中适配器模式的实现方法
在Java开发中,我们常常需要用到Java接口型模式中的适配器模式,那适配器设计模式到底是什么模式呢? 适配器模式(Adapter)就是把一个类的接口变换成客户端所期待的另一种接口,从而使原本接口不匹 ...
- 【Luogu】P3760异或和(权值树状数组)
题目链接 再次声明以后我见到位运算一定第一时间想把它拆成每一位算 本题就是有个前缀和sum[],然后让你求每一位有多少对i,j满足sum[i]-sum[j]在那一位上是1 考虑怎样才能减出1来 如果s ...
- MPLAB® XC C编译器的Workstation License的获取及安装方法
MPLAB®XC C编译器的Workstation License获取及安装方法如下:首先需要购买获得一个XC C编译器的激活码,然后到以下网页(http://www.microchip.com/rl ...
- 冒泡排序 [组合数学+dp]
题面 思路 一眼看过去以为NOI2018的题出出来了= =贼吓人 首先,对于这个难度,我们有一个比较明显的结论: 一个序列的难度,等于这个东西: $hard=max(\sum_{j=i+1}^n[a_ ...
- 享元模式(FlyWeight Pattern)及其在java自动拆箱、自动装箱中的运用
本文主要从三个方面着手,第一:简要介绍享元模式.第二:享元模式在基本类型封装类中的运用以Integer为例进行阐述.第三:根据第一.第二的介绍,进而推出java是如何实现自动拆箱与装箱的. 第一:简要 ...
- 关于tbody js取法兼容。
本来jquery就是为了兼容才用的,动态添加表格的时候,ie必须要append 到tbody上,不然无法取上. 而chrome等则可以,最终还是选appendto tobody