歌手 IU
背景故事:
这段时间在优化公司APP的过程中,发现内存泄漏这一块特别严重,这里总结记录一下。
什么是内存泄漏?
本应释放的内存没有释放,导致可用空间减少的现象。(摘自百度知道,看你敢不敢信)
举个例子:你dismiss了一个视图控制器,但是最终却没有执行这个视图控制器的dealloc方法。
目前遇到的导致内存泄漏比较严重的有这几个地方:
一.delegate
不知为何之前那个开发者全部用的retain修饰符,导致很多应该释放的视图控制器都没释放。这个修改很简单:将retain改成weak即可。
二.block
不管是自己写的block、还是三方的甚至系统的,都要小心,尤其是当你对循环引用没有较好的把控时,更是要当心再当心,多一个心眼总是没错的。
比如说使用MJRefresh时,这样写会导致内存泄漏:
self.tableView.header = [CQHeader headerWithRefreshingBlock:^{ [self getLocation]; }];
这样写则不会:
__weak typeof (self) weakSelf = self; self.tableView.header = [CQHeader headerWithRefreshingBlock:^{ [weakSelf getLocation]; }];
一般我们会将weakSelf和strongSelf配合使用。
三.timer
根据实际情况在恰当时间主动将timer置为nil。
[_timer invalidate]; _timer = nil;
如果还有哪些容易导致内存泄漏的,希望大家补充。
如何更好的监测内存泄漏?
目前我是用的微信读书团队的一个开源库:MLeaksFinder,这个库使用非常简单,效果也不错:调试的时候如果遇到内存泄漏就会弹窗提示,虽然只是view和viewController的,但是大部分时候够用了,强烈建议没用过的同学试试。
值得一提的是,这个库是二锤经纪人告诉我的,一个很给力、很强势的小伙子。
强势的二锤经纪人
当然,仅仅是借助一个三方工具肯定是不够的。
对内存的把控跟开发者的经验和水平有关,作为经验和水平都一般的开发者(说的就是我自己)不能保证代码一定没有内存泄漏,那么如何尽量避免内存泄漏呢?我觉得除了对常见的内存泄漏有所了解外,更需要一种意识:保持警惕和密切注视的意识——
开发的时候保持警惕:
每当遇到delegate、block和timer时就告诉自己:这家伙会导致内存泄漏,要小心。
调试的时候密切注视:
调试的时候注意观察Memory的变化,如果你的循环往复操作都能导致内存只增不减,那肯定是有内存泄漏了。另外结合MLeaksFinder这个实用工具,我们可以第一时间发现内存泄漏问题,但是MLeaksFinder却不能帮我们发现所有的内存泄漏,我自己也遇到过这种情况,MLeaksFinder提示已经dealloced但是instrument中又显示有内存泄漏,并且官方也说了MLeaksFinder只能检查大部分内存泄漏。所以,instrument才是检查内存泄漏的终究武器,尽量用instrument检查内存泄漏。
还是那句话,意识最重要,让意识成为习惯,习惯主宰胜利。
如果我们每写好一个页面或一个模块都用instrument检查一下,我相信,绝对会大大较少内存泄漏的概率。
注意
调用了视图控制器dealloc方法并不能说明这个视图控制器中就没有内存泄漏了,因为:
dealloc 执行只能保证本对象里面没有存在的内存泄漏点,但是不保证本对象所持有的其他对象,以及其他对象所持有的其他对象没有内存泄漏,要保证没有内存泄漏,要保证所有对象的dealloc 都要执行 。 ——来自CocoaChina版主的回答
一张图证明版主说的是对的:
即使存在明显的内存泄漏还是执行了dealloc方法
很明显的内存泄漏,但是视图控制器的dealloc方法还是执行了,instrument里也显示存在内存泄漏。
最后
如果大家有更好更实用的方法,欢迎分享。如果发现文中所述有什么不妥的地方,欢迎直接指出。
作者:无夜之星辰
來源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。