iOS/OS X 内存管理(二):借助工具解决内存问题
2023-09-14 08:57:28 时间
tableViewStyle:UITableViewCellStyleDefault
configureCellBlock:^(UITableViewCell *cell, NSString *item, NSIndexPath *indexPath) {
要想通过tableView显示数据,首先要实现UITableViewDataSource这个协议,为了瘦身controller和复用data source,我将它分离到一个类ArrayDataSource来实现UITableViewDataSource这个协议。然后在viewDidLoad方法里面将dataSource赋值给tableView.dataSource。 解释完NameListViewController的职责后,接下来我们需要思考出现EXC_BAD_ACCESS错误的原因和位置信息。 一般来说,出现EXC_BAD_ACCESS错误的原因都是悬挂指针导致的,但具体是哪个指针是悬挂指针还不确定,因为控制台并没有给出具体crash信息。 启用NSZombieEnabled 要想得到更多的crash信息,你需要启动NSZombieEnabled。具体步骤如下: 1.选中Edit Scheme,并点击
2.Run - Diagnostics - Enable Zombie Objects
设置完之后,再次运行和点击悬挂指针,虽然会再次crash,但这次控制台打印了以下有用信息:
信息message sent to deallocated instance 0x7fe19b081760大意是向一个已释放对象发送信息,也就是已释放对象还调用某个方法。现在我们大概知道什么原因导致程序会crash,但是具体哪个对象被释放还仍然使用呢?
点击上面红色框的Continue program execution按钮继续运行,截图如下:
留意上面的两个红色框,它们两个地址是一样,而且ArrayDataSource前面有个_NSZombie_修饰符,说明dataSource对象被释放还仍然使用。
再进一步看dataSource声明属性的修饰符是assign
而assign对应就是__unsafe_unretained,它跟__weak相似,被它修饰的变量都不持有对象的所有权,但当变量指向的对象的RC为0时,变量并不设置为nil,而是继续保存对象的地址。 因此,在viewDidLoad方法中
* 而self.tableView.dataSource也不是strong,而是weak,此时仍然使用,所有会导致程序crash
分析完原因和定位错误代码后,至于如何修改,我想大家都心知肚明了,如果还不知道的话,留言给我。 内存泄露问题 还记得上一篇iOS/OS X内存管理(一):基本概念与原理的引用循环例子吗?它会导致内存泄露,上次只是文字描述,不怎么直观,这次我们尝试使用Instruments里面的子工具Leaks来检查内存泄露。 静态分析 一般来说,在程序未运行之前我们可以先通过Clang Static Analyzer(静态分析)来检查代码是否存在bug。比如,内存泄露、文件资源泄露或访问空指针的数据等。下面有个静态分析的例子来讲述如何启用静态分析以及静态分析能够查找哪些bugs。 启动程序后,点击静态分析,马上就出现crash
此时,即使启用NSZombieEnabled,控制台也不能打印出更多有关bug的信息,具体原因是什么,等下会解释。
打开StaticAnalysisViewController,里面引用Facebook Infer工具的代码例子,包含个人日常开发中会出现的bugs:
手动静态分析:每次都是通过点击菜单栏的Product - Analyze或快捷键shift + command + b
自动静态分析:在Build Settings启用Analyze During Build,每次编译时都会自动静态分析
静态分析结果如下:
通过静态分析结果,我们来分析一下为什么NSZombieEnabled不能定位EXC_BAD_ACCESS的错误代码位置。由于callback传入进来的是null指针,而NSZombieEnabled只能针对某个已经释放对象的地址,所以启动NSZombieEnabled是不能定位的,不过可以通过静态分析可得知。
启动Instruments
有时使用静态分析能够检查出一些内存泄露问题,但是有时只有运行时使用Instruments才能检查到,启动Instruments步骤如下:
1.点击Xcode的菜单栏的 Product - Profile 启动Instruments
2.此时,出现Instruments的工具集,选中Leaks子工具点击
3.打开Leaks工具之后,点击红色圆点按钮启动Leaks工具,在Leaks工具启动同时,模拟器或真机也跟着启动
4.启动Leaks工具后,它会在程序运行时记录内存分配信息和检查是否发生内存泄露。当你点击引用循环进去那个页面后,再返回到主页,就会发生内存泄露
内存泄露.gif
如果发生内存泄露,我们怎么定位哪里发生和为什么会发生内存泄露?
定位内存泄露
借助Leaks能很快定位内存泄露问题,在这个例子中,步骤如下:
首先点击Leak Checks时间条那个红色叉
然后双击某行内存泄露调用栈,会直接跳到内存泄露代码位置
分析内存泄露原因
上面已经定位好内存泄露代码的位置,至于原因是什么?可以查看上一篇的iOS/OS X内存管理(一):基本概念与原理的循环引用例子,那里已经有详细的解释。
难以检测Block引用循环
大多数的内存问题都可以通过静态分析和Instrument Leak工具检测出来,但是有种block引用循环是难以检测的,看我们这个Block内存泄露例子,跟上面的悬挂指针例子差不多,只是在configureCellBlock里面调用一个方法configureCell。
tableViewStyle:UITableViewCellStyleDefault
configureCellBlock:^(UITableViewCell *cell, NSString *item, NSIndexPath *indexPath) {
结果是没有任何内存泄露的提示,我们再用Instrument Leak工具在运行时看看能不能检查出:
结果跟使用静态分析一样,还是没有任何内存泄露信息的提示。
那么我们怎么知道这个BlockLeakViewController发生了内存泄露呢?还是根据iOS/OS X内存管理机制的一个基本原理:当某个对象的引用计数为0时,它就会自动调用- (void)dealloc方法。
在这个例子中,如果BlockLeakViewController被navigationController pop出去后,没有调用dealloc方法,说明它的某个属性对象仍然被持有,未被释放。而我在dealloc方法打印release BlockLeakViewController信息:
在我点击返回按钮后,其并没有打印出来,因此这个BlockLeakViewController存在内存泄露问题的。至于如何解决block内存泄露这个问题,很多基本功扎实的同学都知道如何解决,不懂的话,自己查资料解决吧! 总结 一般来说,在创建工程的时候,我都会在Build Settings启用Analyze During Build,每次编译时都会自动静态分析。这样的话,写完一小段代码之后,就马上知道是否存在内存泄露或其他bug问题,并且可以修bugs。而在运行过程中,如果出现EXC_BAD_ACCESS,启用NSZombieEnabled,看出现异常后,控制台能否打印出更多的提示信息。如果想在运行时查看是否存在内存泄露,使用Instrument Leak工具。但是有些内存泄露是很难检查出来,有时只有通过手动覆盖dealloc方法,看它最终有没有调用。
Application Loader及Transporter App上传ipa外、可以在Windows上架iOS APP工具 随着xcode的更新,苹果公司已经不直接提供Application Loader这个工具上传IPA了,导致上传ipa比较难搞了。 这里分享介绍一个可以在Windows、跨平台申请iOS证书上传ipa的工具Appuploader,方面跨平台开发没有苹果电脑,或者还不熟悉iOS上架流程的开发者使用。 双重验证码登录,安全放心,已帮助上万开发者提交苹果APP!
iOS小技能:【设备日志查看工具】syslog、deviceconsole和socat 本文介绍iOS设备日志查看工具syslog、deviceconsole和`socat`,如果上述工具都不满意,你也可以使用Mac系统自带的console控制台进行查看。
20个可以帮你简化iOS app开发流程的工具 这里推荐20个可以帮你简化iOS app开发流程的工具。很多开发者都使用过这些工具,涉及原型和设计、编程、测试以及最后的营销,基本上涵盖了整个开发过程。
configureCellBlock:^(UITableViewCell *cell, NSString *item, NSIndexPath *indexPath) {
要想通过tableView显示数据,首先要实现UITableViewDataSource这个协议,为了瘦身controller和复用data source,我将它分离到一个类ArrayDataSource来实现UITableViewDataSource这个协议。然后在viewDidLoad方法里面将dataSource赋值给tableView.dataSource。 解释完NameListViewController的职责后,接下来我们需要思考出现EXC_BAD_ACCESS错误的原因和位置信息。 一般来说,出现EXC_BAD_ACCESS错误的原因都是悬挂指针导致的,但具体是哪个指针是悬挂指针还不确定,因为控制台并没有给出具体crash信息。 启用NSZombieEnabled 要想得到更多的crash信息,你需要启动NSZombieEnabled。具体步骤如下: 1.选中Edit Scheme,并点击
![1455702260463590.png 166109-f4e0337f766e1e89.png](http://cc.cocimg.com/api/uploads/20160217/1455702260463590.png)
![1455702297971826.png 166109-ae4f6b55212b75a9.png](http://cc.cocimg.com/api/uploads/20160217/1455702297971826.png)
![1455702322987711.png 166109-9fe90d621bf6ce06.png](http://cc.cocimg.com/api/uploads/20160217/1455702322987711.png)
![1455702351989090.png 166109-654444b25d8c5155.png](http://cc.cocimg.com/api/uploads/20160217/1455702351989090.png)
而assign对应就是__unsafe_unretained,它跟__weak相似,被它修饰的变量都不持有对象的所有权,但当变量指向的对象的RC为0时,变量并不设置为nil,而是继续保存对象的地址。 因此,在viewDidLoad方法中
* 而self.tableView.dataSource也不是strong,而是weak,此时仍然使用,所有会导致程序crash
分析完原因和定位错误代码后,至于如何修改,我想大家都心知肚明了,如果还不知道的话,留言给我。 内存泄露问题 还记得上一篇iOS/OS X内存管理(一):基本概念与原理的引用循环例子吗?它会导致内存泄露,上次只是文字描述,不怎么直观,这次我们尝试使用Instruments里面的子工具Leaks来检查内存泄露。 静态分析 一般来说,在程序未运行之前我们可以先通过Clang Static Analyzer(静态分析)来检查代码是否存在bug。比如,内存泄露、文件资源泄露或访问空指针的数据等。下面有个静态分析的例子来讲述如何启用静态分析以及静态分析能够查找哪些bugs。 启动程序后,点击静态分析,马上就出现crash
![1455702456834408.png 166109-036d86de2b9e9424.png](http://cc.cocimg.com/api/uploads/20160217/1455702456834408.png)
手动静态分析:每次都是通过点击菜单栏的Product - Analyze或快捷键shift + command + b
![1455702602889252.png 166109-a890797a4457159d.png](http://cc.cocimg.com/api/uploads/20160217/1455702602889252.png)
![1455702620911747.png 166109-5c1dcdd871fcb891.png](http://cc.cocimg.com/api/uploads/20160217/1455702620911747.png)
![1455702630773154.png 166109-6c032a57f0fef09b.png](http://cc.cocimg.com/api/uploads/20160217/1455702630773154.png)
![1455702712157999.png 166109-95b4ea305007d321.png](http://cc.cocimg.com/api/uploads/20160217/1455702712157999.png)
![1455702722661805.png 166109-379b199e81584b16.png](http://cc.cocimg.com/api/uploads/20160217/1455702722661805.png)
![1455702752470838.png 166109-03e04393903c0c6d.png](http://cc.cocimg.com/api/uploads/20160217/1455702752470838.png)
![1455702765336340.gif 166109-1148d40299015b5f.gif](http://cc.cocimg.com/api/uploads/20160217/1455702765336340.gif)
![1455702800976860.png QQ截图20160217175300.png](http://cc.cocimg.com/api/uploads/20160217/1455702800976860.png)
![1455702906136270.png 45.png](http://cc.cocimg.com/api/uploads/20160217/1455702906136270.png)
![1455702899486042.png 46.png](http://cc.cocimg.com/api/uploads/20160217/1455702899486042.png)
tableViewStyle:UITableViewCellStyleDefault
configureCellBlock:^(UITableViewCell *cell, NSString *item, NSIndexPath *indexPath) {
![1455703034961910.png 166109-c9f8a4c970462eb6.png](http://cc.cocimg.com/api/uploads/20160217/1455703034961910.png)
![1455703044559251.gif 166109-68e795cea155fd8e.gif](http://cc.cocimg.com/api/uploads/20160217/1455703044559251.gif)
在我点击返回按钮后,其并没有打印出来,因此这个BlockLeakViewController存在内存泄露问题的。至于如何解决block内存泄露这个问题,很多基本功扎实的同学都知道如何解决,不懂的话,自己查资料解决吧! 总结 一般来说,在创建工程的时候,我都会在Build Settings启用Analyze During Build,每次编译时都会自动静态分析。这样的话,写完一小段代码之后,就马上知道是否存在内存泄露或其他bug问题,并且可以修bugs。而在运行过程中,如果出现EXC_BAD_ACCESS,启用NSZombieEnabled,看出现异常后,控制台能否打印出更多的提示信息。如果想在运行时查看是否存在内存泄露,使用Instrument Leak工具。但是有些内存泄露是很难检查出来,有时只有通过手动覆盖dealloc方法,看它最终有没有调用。
Application Loader及Transporter App上传ipa外、可以在Windows上架iOS APP工具 随着xcode的更新,苹果公司已经不直接提供Application Loader这个工具上传IPA了,导致上传ipa比较难搞了。 这里分享介绍一个可以在Windows、跨平台申请iOS证书上传ipa的工具Appuploader,方面跨平台开发没有苹果电脑,或者还不熟悉iOS上架流程的开发者使用。 双重验证码登录,安全放心,已帮助上万开发者提交苹果APP!
iOS小技能:【设备日志查看工具】syslog、deviceconsole和socat 本文介绍iOS设备日志查看工具syslog、deviceconsole和`socat`,如果上述工具都不满意,你也可以使用Mac系统自带的console控制台进行查看。
20个可以帮你简化iOS app开发流程的工具 这里推荐20个可以帮你简化iOS app开发流程的工具。很多开发者都使用过这些工具,涉及原型和设计、编程、测试以及最后的营销,基本上涵盖了整个开发过程。
相关文章
- 专家称Mac OS X、iOS融合 2-3年内还难看到
- Android高配置手机为何没iOS流畅
- iOS开发之SQLite-C语言接口规范(二) —— Prepared Your SQL Statements
- ios 多语言支持
- 关于第三方IOS的checkBox框架的使用
- iOS开发UI篇—IOS开发中Xcode的一些使用技巧
- h5苹果ios系统中overflow: auto滑动不流畅
- 【IOS开发必收藏】详解IOS应用程序内使用IAP/STOREKIT付费、沙盒(SANDBOX)测试、创建测试账号流程!【2012-12-11日更新获取”产品付费数量等于0的问题”】
- IOS中 浅谈iOS中MVVM的架构设计与团队协作
- iOS中 蓝牙2.0详解/ios蓝牙设备详解
- 《iPhone与iPad开发实战—iOS经典应用剖析》连载五
- ios swift UITabBarController present dismiss
- iOS 小组件 widget
- iOS 设计模式 桥接 适配器
- iOS oc swift 通知的简单使用
- iOS:runtime 消息转发 Method_Swizzling 动态添加方法 动态方法解析
- SVG在iOS中的使用
- IOS No devices because active scheme has no targets
- h5在iOS上滑动卡顿问题
- android 自定义仿ios底部DiaLog
- Android 10.0 仿ios的hotseat效果修改hotseat样式
- iOS音视频开发六:音频渲染
- 公布IOS产品被拒后怎样再上传新公布包