概述
Objective-C中没有垃圾回收机制,内存管理是依赖对象引用计数器来进行的。
每个对象内部都有一个与之对应的整数(retainCount)叫“引用计数器”,当一个对象在创建之后它的引用计数器为1,当调用这个对象的alloc、retain、new、copy方法之后引用计数器自动在原来的基础上加1。
通过dealloc方法来查看是否一个对象应经被回收,如果没有被回收则有可能造成内存泄露。
当一个对象被释放后,需要引用它的变量手动设置为nil,否则造成野指针错误(即被释放之后,再一次去访问,发现内存已经被回收,指针瞬间就没有归宿感,犹如离家的孩子,孤独无助),并且在给空对象发送消息是不会引起错误的。
野指针错误形式在Xcode中通常表现为:Thread 1:EXC_BAD_ACCESS(code=EXC_I386_GPFLT) pointer being freed was not allocated,表明指针已经被释放没有被分配,就是说你访问了一块已经不属于你的内存。
黄金法则
如果对一个对象进行了alloc、retain、copy操作,就获取了对应对象的所有权,那么就有义务对其进行release或着autorelease操作。简单来说就是需要遵循一个原则:谁创建,谁释放。
ARC环境下的内存管理
Block引起的循环引用
循环引用:self对block拥有一个强引用,而block内部又对self有一个强引用,形成闭环,发生内存泄露。
解决办法:在MRC中,block不会retain住对象的,但在ARC则会retain住,需要__weak来达到一个弱引用的效果。
- (void)performSelector:引起的内存泄露
运行原理:系统会自动将Object的引用计数+1,直到selector执行完毕后才会将引用计数-1。如果selector一直没用被执行的话,self就一直不能被释放,造成内存泄露。
解决方法:将未执行的perform取消,即[NSObject cancelPreviousPerformRequestWithTarget:self]。
NSTimer的问题
提出问题:NSTimer是用来在未来某个时刻执行一次或多次我们指定的方法,那么系统是如何保证timer出发action时,我们指定的方法是有效的,如果接收不到呢?
运行原理:系统会自动retain住接受者对象,直到我们指定的方法被执行。
解决办法:如果timer被要求执行一次我们指定的方法,系统会自动调用invalidated,而重复性的timer则不会自动调用,一般我们会在dealloc的时候,对timer调用invalidated方法,是timer失效,否则dealloc永远不会被调用,我们需要做的是在dealloc之前调用invalidated。