自动引入ARC机制后,一般的内存管理可以不用我们码农来负责了。但是一些操作如果不注意,还是会引起内存泄漏。
1.内存泄漏原理:
程序中已经动态分配的堆内存由于某种原因程序未释放或无法释放,造成系统内存的浪费,导致程序运行速度减慢甚至系统崩溃等严重后果。
2.常规的检测方法:
2.1 Analyze静态分析
2.2 动态分析(Instrument->Leaks)
3.内存泄漏的场景和分析:
3.1 delegate(weak/strong)
3.2 CoreGraphics框架里申请的内存忘记释放
只有当CGImageRef使用create或retain后才需要手动release; 没有就不需要手动处理了,系统会进行自动释放,否则手动释放会引起crash:CFRelease的对象不能是NULL,若是NULL的话,会引起runtime的错误并且程序要崩溃,本来imageRef的管理者是会在某个时刻调用release的,但是因为这里已经release过了,已经成了NULL,所以当这个调用时期到来的时候就crash掉了
3.3 CoreFoundation框架里申请的内存忘记释放
通过create创建的CGUUIDRef需要执行CFRelease(),否则会引起内存泄漏。使用静态分析可以轻易发现。
__Bridge 是将CoreFoundation框架的对象所有全交给Foundation框架来使用;但是Foundation框架中的对象并不能管理该对象的内存。
__Bridge_transfer 是将CF框架的对象的所有权交给Foundation来管理,如果Foundation中对象销毁,对象CF会一起销毁。所以这种侨接方式,以后就不用再自己手动内存管理了。
3.4 NSTimer不正确使用造成的内存泄漏
3.4.1 NSTimer重复设置为NO,不会引起内存泄漏
3.4.2 NSTimer重复设置为YES,有执行invalidate就不会内存泄漏,没有执行invalid就会内存泄漏,在timer的执行方法里调用invalid也可以
3.4.3 NSProxy的使用(待补充)
3.5 KVO造成的内存泄漏
3.5.1 不移除观察者,会发生不确定的崩溃:
3.5.2 KVO重复移除导致崩溃:父类/子类各自监听了title的变化,如果都dealloc移除的话会引起崩溃。 所以我们可以传入参数context,来指定特定的observer,然后来移除指定的observer
[view addObserver:self forKeyPath:@"frame" options:NSKeyValueObservingOptionNew context:@“Son”];
[_tableView removeObserver:``self forKeyPath:@``"contentOffset" context:``Son``];
3.6 通知造成的内存泄漏
3.6.1 iOS9以后,一般的通知,都不再需要手动移除观察者,系统会自动在dealloc 的时候调用 [[NSNotificationCenter defaultCenter]removeObserver:self]。iOS9以前的需要手动进行移除。
原因是:iOS9 以前观察者注册时,通知中心并不会对观察者对象做 retain 操作,而是进行了 unsafe_unretained 引用,所以在观察者被回收的时候,如果不对通知进行手动移除,那么指针指向被回收的内存区域就会成为野指针,这时再发送通知,便会造成程序崩溃。
从 iOS9 开始通知中心会对观察者进行 weak 弱引用,这时即使不对通知进行手动移除,指针也会在观察者被回收后自动置空,这时再发送通知,向空指针发送消息是不会有问题的。