iOS内存泄漏问题排查思路

100 阅读2分钟

排查方向

一、block循环引用

要加weakSelf,尤其注意多层block嵌套的情况,每一层都要申明strongSelf 。

swift里面的block循环引用编译器没有提示,需要自己注意。

GCD的block不会引起循环引用。

极端情况下,weak 配合strong 也一样会循环引用,比如A持有一个对象B,B持有block C,C里面又引用了A,并且调用block C的函数处于常驻线程中,会导致A即使加了weak strong修饰也不被释放。

二、 定时器的使用

尽量使用GCD timer,少用NSTimer,用了的话及早invalidate。如果一定要用 NStimer,可以加proxy包裹,proxy弱引用NStimer。

GCD timer 就是需要注意初始化之后尽早resume_dispatch,否则释放时会崩溃。

三、 delegate

尽量设为weak属性,如果是delegate数组,可以使用NSProxy、NSHashTable、NSPointerArray等支持弱引用元素的容器来处理。

四、单例的使用

检查你的对象有没有被单例所持有并且是强引用的,例如需要在单例中为了弹窗或者提示而持有了视图(默认情况下我们会使用strong),这样会导致你的视图由于单例不被释放。建议单例使用的外部属性都申明为weak类型

五、copy的使用

对不可变对象copy会导致引用计数增加,在某些极端场景下会导致内存泄漏,尽量使用mutableCopy ,这样不会增加引用计数。

六、malloc/free/memset的使用

malloc必须与free配对,特别注意一些异常情况return之前要free对象。

对象free之前不要对其使用memset,否则会有泄漏 。

memset 应该用在直接申明来创建结构体这种方式,malloc创建出来的不需要memset。

七、KVO和通知

添加观察者和解除观察者要一一对应。KVO的话这个会直接崩溃了。一般的通知在IOS9之前如果没解除观察者会导致泄漏,iOS9之后好像是系统会自动解除了。

常用工具

工具方面,可以使用MLeaskFinder、Instrument、Debug memory Graph等。

 MLeaskFinder 主要用于查找循环引用,有一定的误报,漏报比较少,可以用于初筛。

Instrument 范围比较广,基本所有的泄漏都能查到,而且也能定位到引起泄漏的内存分配的代码,但也有很多误报的,需要自己甄别。

Debug memory graph需要结合Malloc scribble、malloc stack logging一起使用,效果跟instrument差不多,也能定位到大部分引起泄漏的内存分配的代码,但也有漏的和误报的。

最后,如果你以上工具都试过了,还是找不出来泄漏的地方,那就一段段注释代码吧,有时候最笨的方法也是最有效的方法。