# 内存泄露
[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)