企业🤖AI Agent构建引擎,智能编排和调试,一键部署,支持私有化部署方案 广告
# 内存泄露 [toc] ------ # 一、静态分析:使用 Analyze ## 准备工作 设置NSZombieEnabled 这是一个 “EXC_BAD_ACCESS”错误。我们打开XCode的选项:“NSZombieEnabled” 。在crash时可能会给你更多的一些提示信息。 设置步骤: 1:调用edit scheme ![b096ab56c3028887bd50679eb3f76aea.jpg](http://cc.cocimg.com/api/uploads/20141203/1417587808490152.jpg) 2:勾上红色框里的 ![c944e3f9bfbcd8eebbd1692769211d48.jpg](http://cc.cocimg.com/api/uploads/20141203/1417587836983691.jpg) 3、点击 XCode的Analyze就能分析到哪里有内存泄露, 快捷键:shift+command+b。 ![5e8b764f9f77f614057cd02723a58f67.jpg](http://cc.cocimg.com/api/uploads/20141203/1417587915571490.jpg) ------ ## 静态泄露示例 以下情况会有提示 枚举不完全 ![枚举不完全](http://img.blog.csdn.net/20180105152822365?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbG92ZWNocmlzMDA=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast) ------ NSInteger ,int 等混用 ------ if…else… 漏掉情况,导致数值为空,如: ``` CGFloat badgeW; if (IS_IPHONE_5) { badgeW = 15; }else if (IS_IPHONE_6){ badgeW = 17; } self.label.mj_w = badgeW;1234567 ``` 在非iPhone5、6的情况下,badgeW的调用会产生问题。 ------ 使用了 objc_property_t ,没有使用 free来释放 ------ # 二、动态分析:使用Instruments的leaks工具 静态分析不能把所有的内存泄露查出来,有的内存泄露是在运行时,用户操作时才产生的。那就需要用到Instruments了。 1、Product –> Profile ![6ba20f2483dad9690736bf7e2b0c4695.jpg](http://cc.cocimg.com/api/uploads/20141203/1417587996170852.jpg) 2、按上面操作,build成功后跳出Instruments工具,选择Leaks选项,这时候寿司程序也运行起来了,选中list中的项,拖动等操作后,工具显示效果如下: ![这里写图片描述](http://img.blog.csdn.net/20180105152855517?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbG92ZWNocmlzMDA=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast) 红色XX表示内存泄露了。 先在工具栏按下红色的圆形按钮,把工具监视内存的活动停下来。选择Leak,然后点中间十字交叉那,选择Call Tree. 这时候左下角的Call Tree的可选项可以选了。选中Invert Call Tree 和Hide System Libraries,显示如下: ![b2d10389257113411037e650f88e7e3c.jpg](http://cc.cocimg.com/api/uploads/20141203/1417588059291045.jpg) 这时候内存泄露的具体代码找到了,在右边的红色框框里指定了哪个方法出现了内存泄露。 ------ # 三、使用Debug memory graph ![Debug memory graph](http://img.blog.csdn.net/20180105152207345?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbG92ZWNocmlzMDA=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast) 黑色实线部分为强应用,灰色线为弱引用。 如果你的app已经离开控制器A,A和A中的控件还保存在内存中时,你可以通过这个来查看他们的引用关系。 ![iOS 内存泄露](http://img.blog.csdn.net/20180105152638946?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbG92ZWNocmlzMDA=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast) ------ # 动态分析的泄露示例 这种类型是单例,运行过程中一直保存在内存中,不需要处理。 ![iOS 内存泄漏](http://img.blog.csdn.net/20180105152907657?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbG92ZWNocmlzMDA=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast) ------ ## block 中`self` 的使用 block中,应该使用weakSelf 定义 ``` /** block 中使用Self */ #define WS(weakSelf) __weak __typeof(&*self)weakSelf = self /** block 中调用cell */ #define WC(weakCell,cell) __weak __typeof(&*cell)weakCell = cell1234 ``` 使用 ``` WS(weakSelf); WC(weakCell, cell); cell.blockModificationClick = ^(){ [weakSelf requestModificationDataWithDeliveryNo:weakCell.model.DeliveryNo]; };12345 ``` ------ ## block中`_` 下划线的使用 `_` 下划线实际上是 `self.`,而非 `weakSelf.` ``` [header setBlockGrayHeaderLabel3OnClick:^{ if (_blockGrayHeaderLabel3OnClick) { _blockGrayHeaderLabel3OnClick(); } }]; 123456 ``` ------ ## 子控件对父控制器的引用 有时候将业务写入子控件,但需要父控制器才能调用部分功能,如modal其他控制器;所以需要引用父控制器。这时父控制器属性应该使用weak来修饰,否则会无法释放。问题本质和上面一样。 `@property (nonatomic, weak) UIViewController *superVC;` ------ ## 私有属性 下面写法会造成内存泄露,建议把newInteger作为属性来写。 ![这里写图片描述](http://img.blog.csdn.net/20180105153957494?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbG92ZWNocmlzMDA=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast) ![这里写图片描述](http://img.blog.csdn.net/20180105154004116?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbG92ZWNocmlzMDA=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)