内存管理

在oc这种面向对象语言里,内存管理是一个重要概念,要想用一门语言写出内存使用效率高而且又没有bug的代码,就得掌握其内存管理模型的种种细节。

1、理解引用计数

oc语言使用引用计数来管理内存,也就是说,每个对象都有个可以递增或递减的计数器,如果想使对象继续存活,那就递增其引用计数,用完之后,就递减其计数,计数变为0,就表示没人关注这个对象了,于是,就可以把它销毁。已经用过ARC的人可能会知道,所有与引用计数有关的方法都是无法编译,然而现在先暂时忘掉这件事,那些方法确实无法用在ARC中,不过本条就是要从oc的角度讲解引用计数,而arc实际上也是一种引用计数机制,所以,还要谈谈这些在开启arc功能是不能直接调用的方法。

引用计数工作原理

在引用计数架构下,对象有个计数器,用以表示当前有多少个事物想令此对象继续存活下去,这在oc中叫做“保留计数”(retain count),不过也可以叫“引用计数”(reference count),NSObject协议声明了下面三个方法用于操作计数器,以递增或递减其值:retain递增保留计数  release递减保留计数  autorelease 待稍后清理“自动释放池”(autorelease pool)时,再递减保留计数。

查看保留计数的方法叫做retainCount,此方法不太有用,即便在调试时也是如此,所以笔者不推荐。

对象创建出来时,其保留计数至少为1,若想令其继续存活,则调用retain方法,要是某部分代码不再使用此对象,不想令其继续存活,那就调用release或autorelease方法,最重当保留计数归零时,对象就回收了,也就是说,系统会将其占用的内存标记为“可重用”,此时,所有指向该对象的引用也都变得无效了。

下图演示了对象自创建出来之后经历一次“保留”及两次“释放”操作的过程。

应用程序在其生命期中会创建很多对象,这些对象相互联系着,例如,表示个人信息的对象会引用另一个表示任命的字符串对象,而且可能还会引用其他个人信息对象,于是,这些相互关联的对象就构成一张“对象图”。对象如果持有指向其他对象的强引用,那么前者就“用友后者”也就是说,对象想令其所引用的那些对象继续存活,就可将其“保留”,等用完以后,再释放。

下图objectb和objectc都引用了objecta,若objectb和objectc都不在使用objecta,则其保留计数降为0,于是便可摧毁了。还有其他对象想令objectb和objectc继续存活,而应用程序又有另外一些对象想令那些对象继续存活,如果按“引用计数”回溯,那么最终会发现一个“根对象”。在mac os x应用程序中,此对象就是NSApplication对象,而在ios应用程序中,则是UIApplication对象,两者都是应用程序启动时创建的单例。


下面代码用于理解

NSMutableArray *array = [[NSMutableArray alloc]init];

NSNumber *number = [[NSNumber alloc]initWithInt:1337];

[array addObject:number];

[number release];

[array release];

由于代码中直接调用了release方法,所以在ARC下无法编译,在oc中,调用alloc方法所返回的对象由调用者所拥有,也就是说,调用者已通过alloc方法表达了想令该对象继续存活下去的意愿,不过请注意,这并不是说对象此时的保留计数必定是1,在alloc或“initWithInt”方法的实现代码中,也许还有其他对象也保留了此对象,所以,其保留计数可能会大于1,能够肯定的是:保留计数至少为1,保留计数这个概念就应该这样来理解才对,绝不应该说保留计数一定是某个值,只能说你所执行的操作使递增还是递减了该计数。

创建完数组后,把number对象加入其中,调用数组的“addObject:”方法时,数组也会在number上调用retain方法,以期继续保留此对象。这是,保留计数至少为2,接下来,代码不在需要number对象了,于是将其释放,现在保留计数至少为1,这样就不能照常使用number变量了,调用release之后,已经无法保证所指的对象仍然存活,因为数组还在引用它,然而绝不应该假设此对象一定存活,也就是说,不要像下面这样编写代码:

NSNumber *number = [[NSNumber alloc]initWithInt:1337];

[array addObject:number];

[number release];

nslog(@"number=%@",number);

即便上述代码可以正常执行,也不是一个好办法,如果调用release之后,基于某些原因,其保留计数为0,那么number对象所占内存也许会回收,这样的话,再调用nslog可能就将使程序崩溃了,笔者在这里说”可能“,而不是”一定“是因为对象所占的内存在”解除分配“之后,只是放回”可用内存池(avaialbe pool)“如果执行nslog时尚未复写对象内存,那么对象仍然有效,这时不会崩溃,由此可见:因过早释放对象而导致的bug很难调试。

为了避免不经意间使用了无效对象,一般调用玩release之后都会清空指针,这就能保证不会出现可能指向无效对象的指针,这种指针通常称为”悬挂指针“,比方说可以这样编写代码防止此情况发生:

NSNumber *number = [[NSNumber alloc]init];

[array addObject:number];

[number release];

number = nil;

以上是笔者在书中摘抄,后续会有自动释放池及arc下的内存管理

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值