内存泄漏

111 阅读3分钟

自动引入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 弱引用,这时即使不对通知进行手动移除,指针也会在观察者被回收后自动置空,这时再发送通知,向空指针发送消息是不会有问题的。