内存泄漏
在日常开发中,时常不小心发生的内存泄漏让每个程序员都非常懊恼,尤其对性能有所追求的同学。有的未及时销毁的对象会持续监听通知,持续KVO,偶来再来几个意想不到的Crash,让开发者措不及防,手足无措。所以在开发阶段就找出内存泄漏、打破循环引用是非常有必要的。
在查找内存泄漏的时候经常使用的方法有以下几种:
| 方法 | 缺点 | 优点 |
|---|---|---|
| 在dealloc打印 | 每个类都需要增加 | 简单 |
| Instruments的Leaks | 耗时长,静态变量也会找出 | 非常的全面,看起来高端 |
| MLeaksFinder | 基于Controller 和 View | 代码无侵入,可扩展 |
结合项目经过横向对比,我们这里采用了集成MLeaksFinder + FBRetainCycleDetector的方式整治内存泄漏。
MLeaksFinder
在集成的时候遇到第一个问题就是FBRetainCycleDetector中有点小问题。 这里有详细的解决方案。 由于我们项目是私有的库的方式集成的,所以这里直接使用改代码的方式来修复这个问题。
MLeaksFinder的原理也比较有意思,基于Controller来定义出来一种新的生命周期节点--
willDealloc,然后倒计时2秒去检查是否真的被释放,如果没有被释放就判定其发生内存泄漏,然后就惊醒弹窗提示。
而其依赖的FBRetainCycleDetector,顾名思义是来检索循环引用的。如果出现循环引用也可以快速定位循环引用的位置,从而打破引用,修复内存泄漏。如果对代码比较熟悉或者不想依赖这个库可以剔除相关代码。
使用情况举例
可以看到VC发生了内存泄漏,如果需要进一步发现循环引用,点击“Retain Cycle”。
这里就需要进一步查看代码:
可以看到这里的Block对self进行了捕捉,从而造成了引用,产生了循环引用。只需要将90行代码往上移动即可修复。
容易发生泄漏与解决方案
在使用的过程中发现重灾区有以下2种,一种是Blcok造成的循环引用,一种是定时器引发的。
ViewModel/View的Block
在一些ViewModel和View的Block复制的时候,会不小心捕捉引用当前ViewControler。而ViewController对ViewModel和View有引用,这种情况也会产生循环引用。
这种的比较好解决,直接使用我们的”强弱共舞“即可。
详情可以参考之前 Block 循环引用。
Timer/CADispaly的Target
有的地方,需要用到定时器,也是非常容易引起循环引用。例如:
其中当前类的View强引用display。
想要打破这种循环引用就需要用到NSProxy了。我这里就不单另重新生成新类了,直接使用YYText中的YYTextWeakProxy了。
这样就成功的解决了内存泄漏。