iOS内存泄漏整改

454 阅读3分钟

内存泄漏

在日常开发中,时常不小心发生的内存泄漏让每个程序员都非常懊恼,尤其对性能有所追求的同学。有的未及时销毁的对象会持续监听通知,持续KVO,偶来再来几个意想不到的Crash,让开发者措不及防,手足无措。所以在开发阶段就找出内存泄漏、打破循环引用是非常有必要的。

在查找内存泄漏的时候经常使用的方法有以下几种:

方法缺点优点
在dealloc打印每个类都需要增加简单
Instruments的Leaks耗时长,静态变量也会找出非常的全面,看起来高端
MLeaksFinder基于Controller 和 View代码无侵入,可扩展

结合项目经过横向对比,我们这里采用了集成MLeaksFinder + FBRetainCycleDetector的方式整治内存泄漏。

MLeaksFinder

在集成的时候遇到第一个问题就是FBRetainCycleDetector中有点小问题。 这里有详细的解决方案。 由于我们项目是私有的库的方式集成的,所以这里直接使用改代码的方式来修复这个问题。

image.png MLeaksFinder的原理也比较有意思,基于Controller来定义出来一种新的生命周期节点--willDealloc,然后倒计时2秒去检查是否真的被释放,如果没有被释放就判定其发生内存泄漏,然后就惊醒弹窗提示。

而其依赖的FBRetainCycleDetector,顾名思义是来检索循环引用的。如果出现循环引用也可以快速定位循环引用的位置,从而打破引用,修复内存泄漏。如果对代码比较熟悉或者不想依赖这个库可以剔除相关代码。

使用情况举例

image.png

可以看到VC发生了内存泄漏,如果需要进一步发现循环引用,点击“Retain Cycle”。

image.png

这里就需要进一步查看代码:

image.png 可以看到这里的Block对self进行了捕捉,从而造成了引用,产生了循环引用。只需要将90行代码往上移动即可修复。

容易发生泄漏与解决方案

在使用的过程中发现重灾区有以下2种,一种是Blcok造成的循环引用,一种是定时器引发的。

ViewModel/View的Block

在一些ViewModelViewBlock复制的时候,会不小心捕捉引用当前ViewControler。而ViewControllerViewModel和View有引用,这种情况也会产生循环引用。 这种的比较好解决,直接使用我们的”强弱共舞“即可。

详情可以参考之前 Block 循环引用

Timer/CADispaly的Target

有的地方,需要用到定时器,也是非常容易引起循环引用。例如:

image.png 其中当前类的View强引用display。

想要打破这种循环引用就需要用到NSProxy了。我这里就不单另重新生成新类了,直接使用YYText中的YYTextWeakProxy了。

image.png 这样就成功的解决了内存泄漏。

参考链接🔗