已习惯于arc帮我们管理内存的我们,写起代码来,比MRC似乎肆意妄为了许多,总有些有恃无恐的感觉,其实arc下面还是很容易引起内存溢出的。
ARC 是帮助我们做对象内存管理的一套机制,使得我们以前在 MRC 模式下管理内存工作量能在 ARC 模式下得到缓解。正如苹果官方文档上所描述的:
Automatic Reference Counting (ARC) is a compiler feature that provides automatic memory management of Objective-C objects.
可见 ARC 是编译时特性,它没有改变 Objective-C 引用计数式内存管理的本质,更不是 GC(垃圾回收)。
也就是说只要我们稍不注意,隐式的持有或复制对象就会造成内存泄露。
NSNotificationcenter
1 | [[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(method:) name:@"notiName" object:nil]; |
这里添加观察者其实是不会造成内存泄漏的,但是,但是,但是……如果self被销毁,当在调用post消息的时候,就会报对象被释放的错误,导致闪退,所以在添加观察者的对象,一定要在它被销毁的时候从消息中心删除!
就是在注册通知的地方加上这个:
1 | - (void)dealloc { |
NSTimer
1 | timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(method:) userInfo:nil repeats:YES]; |
上面的timer为了防止 target 被释放而导致的程序异常,timer 会持有 target, self 持有 timer,timer 在初始化时持有 self,造成循环引用。解决的方法就是使用 invalidate
方法销掉 timer。
delegate属性的强引用
把delegate
声明为strong
属性容易导致内存溢出 。
解决办法是把delegate
属性的strong
改为assign
或者weak
即可。
- 当用
weak
或assign
修饰的时候,指明该对象并不负责保持delegate
这个对象,delegate
这个对象的销毁由外部控制。
- 当用
strong
修饰的时候,该对象强引用delegate
,外界不能销毁delegate
对象,会导致循环引用(Retain Cycles
)。
WKWebView
1 | [_webView.configuration.userContentController addScriptMessageHandler:self name:clickName]; |
添加addScriptMessageHandler之后,必须在vc销毁前把它移除。
1 | [_webView.configuration.userContentController removeScriptMessageHandlerForName:clickName]; |
和NSNotification
很类似。
Block
上面图片中就是一典型案例,红色部分就是修改之前导致内存溢出的代码,我们来分析一下:
上面的success block应该是self持有,而在success中有持有了self,导致self和 block 的循环引用,造成内存泄露!
说到底还是造成了循环引用导致了内存泄漏,所以我们要打破循环,释放对象,这里我们把self变成了弱引用,打破循环引用。
以上几种情况可能通过instrument 是查看不出来的,至少是没有小红叉的。我们通过instruments查看所有VC的引用计数才找到那些VC是发生了内存泄露。