iOS易引起内存泄漏的原因总结

2019-04-03  本文已影响0人  Cofey_c

一、循环引用

1. 在Block中使用self关键字

解决方案
解决办法: 在Block中使用weakSelf打破循环引用。

2. 在Blcok中访问对象的实例变量

解决方案
建议在Block中使用实例变量时显式指出self.weakSelf.,通过显式指出,可以在一定程度上提示开发人员注意解决self持有问题

3. 在Block中使用super关键字

解决方案
(1) 使用super时确保该Block不会被对象持有链持有
(2) 将相关super的调用包装成一个方法,在Block中使用weakSelf去调用该方法。

4. Block中使用宏定义

解决方案
(1) 尽量避免在宏定义中使用self关键字。
(2) 同时在Block中使用宏定义时做到全面的检查。

5. 在Block中使用持有Block的变量

解决方案
解决方案与第一点相同,打破持有循环就可以,推荐在block中使用weakModel

二、其他需要注意的内存泄漏问题

1. 使用NSTimer

解决方案
(1) 在Timer持有的对象想要释放时手动停止Timer。
(2) 打破Timer对target的强持有,具体方案可参考YYWeakProxy

2. 使用NSURLSessionTask及其子类

解决方案
在代码对NSURLSessionTask及其子类对象失去引用前,需要为该对象调用cancelresume方法,使之脱离挂起状态。

3. MRC与ARC混编

解决方案
(1) 对于使用--fno-objc-arc明确指定的文件,要做到手动管理内存,同时建议对该文件提供的功能进行Leaks检测。
(2) 同时对于已经进行release的对象,应当避免再次访问,以防止触发野指针访问。建议对release之后的变量进行置空操作。

4. CoreFoundationFoundation的桥接

使用带copy字眼的函数创建了CoreFoundation对象,进而桥接为Foundation对象,此时Foundation对象由ARC负责管理,而CoreFoundation对象则没有对应的释放,进而造成内存泄漏。

使用__bridge_retainedFoundation对象桥接至CoreFoundation对象,此时Foundation对象由ARC负责管理,而CoreFoundation对象则没有对应的释放,进而造成内存泄漏。

解决方案
(1) __bridge
该桥接方法可以将CoreFoundation对象与Foundation对象进行桥接,桥接前后对于被桥接的对象没有计数的改变。
(2) __bridge_retained
一般用在将Foundation对象桥接为CoreFoundation对象,该方法会使得对象计数增加,所以需要开发者对桥接后的CoreFoundation对象进行相应的计数减少。关于减少CoreFoundation对象计数的注意事项,有以下几点:

  • 在将CoreFoundation对象进行计数减少后,为避免再次访问该对象可能造成野指针访问,建议及时将对象置为NULL,
  • 对于CoreFoundation框架对象来说,可以使用CFRelease函数进行计数减少,需要注意的是,在调用该函数前要对对象进行NULL检查,CFRelease函数在对NULL操作时会发生崩溃。
  • 对于某些类型的CoreFoundation对象,可以使用特有的减少计数方法,例如:CGImageRef对象可以使用CGImageRelease函数,CGFontRef对象可以使用CGFontRelease函数。但是具体函数是否封装了对NULL的检测,需要查看函数介绍,CGImageRefCFRelease相同未检测NULLCGFontRelease函数说明为/* Equivalent toCFRelease(font)', except it doesn't crash (as CFRelease does) if font' is NULL. */,封装了NULL的检测。

5. malloc的使用

解决方案

  • 正常情况下我们在函数中使用malloc一般都会对应free,但在使用将malloc申请的内存作为返回值的函数时,很有可能遗忘对内存的释放。建议在使用返回指针的函数时要特别注重这类问题,同时函数的文档中也需要特别指出返回值需要调用者手动释放,避免调用者遗忘。
  • 同时调用者在进行free之前,需要对指针进行NULL的检测。
  • 在调用NSData的+ (instancetype)dataWithBytesNoCopy:(void *)bytes length:(NSUInteger)length;方法或+ (instancetype)dataWithBytesNoCopy:(void *)bytes length:(NSUInteger)length freeWhenDone:(BOOL)b;且传入YES时,会对bytes进行释放,无需显示调用free来释放bytes
上一篇下一篇

猜你喜欢

热点阅读