ios leaks afnetworking3.0多处内存泄露怎么回事
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ios leaks afnetworking3.0多处内存泄露怎么回事相关的知识,希望对你有一定的参考价值。
1、运行Demo。先下载一个实现准备好的内存泄露的Demo吧:leak app
下载下来,打开运行,程序是一个寿司的列表,列出各种寿司卷。试着选择里面的几行,应该是选第二行的时候就崩溃了。崩溃截图:
在崩溃的地方断住了,知道crash的地方了,但是不知道具体crash的原因。
2、设置NSZombieEnabled
这是一个 “EXC_BAD_ACCESS”错误。我们打开XCode的选项:“NSZombieEnabled” 。在crash时可能会给你更多的一些提示信息。
设置步骤:1
2:勾上红色框里的
运行,按刚才的操作选中其中的cell。再次crash,这次在output窗口会看到多了一项错误信息:
2012-11-28 13:22:08.911 PropMemFun[2132:11303] *** -[CFString respondsToSelector:]: message sent to deallocated instance 0x713ebc0
大概意思是:向已释放的内存发送消息。也就是说使用了已释放的内存,在C语言相当于使用了“野指针”
看了下crash的这个语句,sushiString应该是没问题的,它是从stringWithFormat初始化出来的。那就是_lastSushiSelected的问题。
_lastSushiSelected指向了sushiString,sushiString是一个autorelease变量。 在第二次点击时,使用的是sushiString已经被释放,所以crash了。那为_lastSushiSelected保留一下,就可以用了。代码修改如下:
[cpp] view plaincopy
<span style="font-size: 14px;"> _lastSushiSelected = [sushiString retain];
</span>
[cpp] view plain copy
<span style="font-size:14px;"> _lastSushiSelected = [sushiString retain];
</span>
运行,这时候不崩溃。
3、分析内存泄露(shift+command+b)
app不crash了,那看看有没有内存泄露。用XCode的Analyze就能分析到哪里有内存泄露
分析之后可以看到:
这里提示alertView没被释放,有内存泄露,那我们释放
[alertView release];
再分析,这个问题解决了。
4、使用Instruments的leaks工具
分析内存泄露不能把所有的内存泄露查出来,有的内存泄露是在运行时,用户操作时才产生的。那就需要用到Instruments了。
按上面操作,build成功后跳出Instruments工具,选择Leaks选项,这时候寿司程序也运行起来了,选中list中的项,拖动等操作后,工具显示效果如下:
大家可能都能猜到,红色的柱子表示内存泄露了。怎么通过这个工具看到在哪泄露了呢?
先在工具栏按下红色的圆形按钮,把工具监视内存的活动停下来。选择Leak,然后点中间十字交叉那,选择Call Tree.
这时候左下角的Call Tree的可选项可以选了。选中Invert Call Tree 和Hide System Libraries,显示如下:
这时候内存泄露的具体代码找到了,在右边的红色框框里指定了哪个方法出现了内存泄露。
你只要在这些方法上双击,就会跳转到具体的代码,哈哈,是不是很方便。
这里应该是提示100%内存会泄露。
6、解决内存泄露问题
问题找到了,那就解决吧
关于:tableView:didSelectRowAtIndexPath ,分析下它的内存过程:
sushiString变量通过autorelease创建,它的引用计数是1.
这行代码使得引用计数增加到2, _lastSushiSelected = [sushiString retain];
这个方法结束时,sushiString的autorelease生效了,这个变量的引用计数减少为1
当再次执行tableView:didSelectRowAtIndexPath这个方法时,_lastSushiSelected被赋值了新指针,老的_lastSushiSelected的引用计数还是1,没有被释放,产生了内存泄露。
怎么解决呢?
在_lastSushiSelected = [sushiString retain];之前把原来的release就ok了:
[cpp] view plaincopy
<span style="font-size: 14px;"> [_lastSushiSelected release];
_lastSushiSelected = [sushiString retain];</span>
[cpp] view plain copy
<span style="font-size:14px;"> [_lastSushiSelected release];
_lastSushiSelected = [sushiString retain];</span>
关于:tableView:cellForRowAtIndexPath
这个比较明显,sushiString被alloc和init之后就没有释放,可以用stringWithFormat来调用autorelease,代码如下:
[cpp] view plaincopy
<span style="font-size: 14px;">NSString *sushiString = [NSString stringWithFormat:@"%d: %@", indexPath.row, sushiName];</span>
[cpp] view plain copy
<span style="font-size:14px;">NSString *sushiString = [NSString stringWithFormat:@"%d: %@", indexPath.row, sushiName];</span>
好了,泄露都fix了,再用工具分析看看,这时候你再点,再拖,再怎么操作,都没有内存泄露了。表明内存泄露被堵住了。 参考技术A 用xcode打开自己的工程,按快捷键command+r 运行需要测试的程序。
2
点击xcode导航栏的“show the debug navigator”,切换到debug模式
然后选中“Memory”,再点击右侧的 “Profile in Instruments”,会自动打开Instruments。
这时候会弹出来一个对话框,选择“Transfer”
打开后,这时界面如图:
然后切换到ios模拟器,点击那个测试按钮
这个时候会弹出一个对话框,
“cancel”取消对话框后,多点几次“button”,切换到Instruments会发现 “Leaks”一栏里有几个红色的区块。
这就是内存泄露了。
点击暂停,
然后点击“Leaks”一栏
然后点击“导航栏”切换到“call tree”模式下
看到列表里列出了内存泄露的调用逻辑:
勾选右边的详细窗口中的“hide system libraries”,隐藏系统函数。
这个时候就可以清楚看到我们自己程序中的方法调用层次结构了。
展开后,可以发现是[ViewController onTestLeakBtn].
鼠标双击“[ViewController onTestLeakBtn ]”这一行,会跳转到代码。
剩下的工作就是修改代码,然后重复以上步骤。直到没有内存泄露为止。 参考技术B dsffdsfdfdfsffd
iOS性能优化之Leaks动态分析
iOS性能优化之Leaks动态分析
Instruments-Leaks有很多跟踪模块可以动态分析和跟踪内存, CPU 和文件系统(因为是动态分析 所以必须运行才能打开)。
具体使用
- 在XCode Open菜单下,点击Leaks 对App进行动态分析(快捷键CMD + i)
或者直接在工程中选择调试导航
在右侧点击Profile in instruments
检测图:
Separate by Thread:按线程分开做分析,这样更容易揪出那些吃资源的问题线程。特别是对于主线程,它要处理和渲染所有的接口数据,一旦受到阻塞,程序必然卡顿或停止响应。
Invert Call Tree:反向输出调用树。把调用层级最深的方法显示在最上面,更容易找到最耗时的操作。
Hide Missing Symbols:隐藏缺失符号。如果dSYM文件或其他系统架构缺失,列表中会出现很多奇怪的十六进制的数值,用此选项把这些干扰元素屏蔽掉,让列表回归清爽。
Hide System Libraries:隐藏系统库文件。过滤掉各种系统调用,只显示自己的代码调用。
Flattern Recursion:拼合递归。将同一递归函数产生的多条堆栈(因为递归函数会调用自己)合并为一条。
双击就可以定位到具体的代码了。
更多参考:
ios Instruments之Allocations
iOS Instruments之Leaks
iOS 性能优化:Instruments 工具的救命三招
以上是关于ios leaks afnetworking3.0多处内存泄露怎么回事的主要内容,如果未能解决你的问题,请参考以下文章