现在的项目都是ARC,省去了手动管理内存的麻烦。但是ARC也不是全能的,项目大了内存也会泄漏,而且更难定位。
像block循环引用,time的释放问题都能造成循环引用。下面两张图我觉得能很好的诠释了循环引用:
问题:最近在开发一个阅读模块的功能,点进阅读再退出来,内存居然暴涨了30多MB,多点几次那还不跪下了,这是不可原谅的。于是开始了查找内存泄漏的坎坷旅程。
简单介绍下项目:阅读模块主要类有,阅读ViewController(6878行)->阅读ContentView(4690行)->阅读PdfView(2951行)->计算类(1224行),总共 15743行,还不包括解析。好吧,列出这么多行代码只想说明代码的复杂性,并不是一眼就能看出哪里泄漏了。下面就是整个分析的过程了:
1.最先注意到的是Memory,30MB的增加,肯定引起了我的注意。
2.Debug Memory Graph能看出那些类没有释放,像全局的会一直存在:如单例。
点进阅读再返回,按道理阅读的类都应该释放,却发现这几个阅读相关的类都没有释放
3.于是我默默的打开了Instruments->Leaks,心想肯定能找出来了
发现leaks并没有把这个当做内存泄漏,这就有点难为我了。
这个NSKVONotifying_PdfView有点眼熟,仔细想想,PdfView使用了KVO产生的中间类(幸亏对KVO的原理还是了解的)。虽然没有找出来具体问题,但知道了大概的方向,只能死磕PdfView了。
距离项目上线只有一天,我不确定能否在上线之前找出问题来。但这是必须找出来的,这是责任啊。工具具体定位不到,只能手动查找了,发挥我机智的大脑。
1.定位到了KVO,就朝这方面去看吧。我注释了PdfView中的KVO,再查NSKVONotifying_PdfView没有了,但PdfView没释放。排除不是KVO引起的。
2.由Debug Memory Graph定位到CMWDTextLayout,CMWDTextLine,CMWDTextRun没有释放,我在PdfView中进行手动释放,NSKVONotifying_PdfView依然没有释放。
3.找到PdfView中最重要的几个部分:如绘制模块,KVO赋值模块。逐个进行排查,发现NSKVONotifying_PdfView没有释放。
4.最后都绝望的时候,从初始化的方法开始排查,幸运的是我在initWithFrame方法中找到了下面这个代码:
于是我很快的加上了__weak typeof(self) weakSelf = self;完美的解决了。