内存管理
文章目录
理解引用计数
其实引用计数的内容主要是这一张图片的内容
主要有下面三个方法用来操作计数器
- Retain 递增保留计数
- release 递减保留计数
- autorelease 稍后清理自动释放池子,在递减保持计数
对象创建出来的时候,他保留计数至少要为1,若想让他继续存活,则要调用retain方法。下面我们来看一个例子,来理解这个概念:
NSMutableArray *array = [[NSMutableArray alloc] initl;
NSNumber *number = [ [NSNumber alloc] initWithInt:1337];
[array addobject: number] ;
[number releasel;
[array release];
如前所述,由于代码中直接调用了release 方法,所以在ARC 下无法编译。在Objective-C中,调用alloc 方法所返回的对象由调用者所拥有。也就是说,调用者已通过alloc 方法表达了想令该对象继续存活下去的意愿。不过请注意,这并不是说对象此时的保留计数必定是1。在 alloc或“initWithint:”方法的实现代码中,也许还有其他对象也保留了此对象,所以,其保留计数可能会大于1。能够肯定的是:保留计数至少为1。保留计数这个概念就应该这样来理解才对。绝不应该说保留计数一定是某个值,只能说你所执行的操作是
递增了该计数还是递减了该计数。创建完数组后,把 number 对象加入其中。调用数组的“addObject:” 方法时,数组也会在 number 上调用 retain 方法,以期继续保留此对象。这时,保留计数至少为2。接下来,代码不再需要 number 对象了,于是将其释放。现在的保留计数至少为1。这样就不能照常使用number 变量了。调用 release 之后,已经无法保证所指的对象仍然存活。当然,根据本例中的代码,我们显然知道 number 对象在调用了release之后仍然存活,因为数组还在引用着它。
其实这段话的意思是我们理解引用计数不是简单的理解为1,而是理解长持有一个数,某些操作增加计数或者是减少计数
属性存取方法的内存管理
如果是strong关系。
[obj retain];
[_obj release];
_obj = obj
那么这个方法会先保留新值并释放旧值,然后更新实例变量,让他指向新值。假如还未保留新值在释放旧值的时候,两个值有指向同一个对象,先执行的release 可能会导致此对象永远回收,这个实例变量就变成了一个悬挂指针。所以这个县retain再release的顺序很重要。
自动释放池
在 Objective-C 的引用计数架构中,自动释放池是一项重要特性。调用 release会立刻递减对象的保留计数(而且还有可能令系统回收此对象),然而有时候可以不调用它,改为调用autorelease,此方法会在稍后递减计数,通常是在下一次“事件循环”(event loop)时递减,不过也可能执行得更早些。
这里我们来看一个方法:
- (NSString*) stringValue {
NSString *str = [ [NSString alloc] initWithFormat:@"I am this: %@", selfl;
return str;
}
这里的保留计数会比原先多1,我们要讲多出来的一次保留操作给抵消掉,不过不能再方法内释放str,否则还没等方法返回,系统就把这个对象回收了,这里我们可以采用autorelease
,这样我们就可以正常使用这个函数了。这个方式可以保证对象在跨越方法调用别界后一定存活。
要点
- 引用计数机制通过可以递增递减的计数器来管理内存,对象创建好之后,其保留计数至少为1,若保留计数正,则对象继续存活,保留计数降到0以后,对象就被销毁了。
- 在对象生命周期中,其余对象通过引用来保留或释放此对象,保留操作会递增计数,释放会递减计数
以ARC简化引用计数
在有ARC之后,程序猿其实就没必要担心内存管理问题了。使用ARC来进行编程可以省去很多代码。
ARC会自动执行我们的retain,release方法,所以不能在ARC环境下直接调用这些内存管理方法
使用ARC时必须遵循的方法命名规则
- alloc
- new
- copy
- mutableCopy
如果方法名不易上述这四个词语开头,则表示其所返回的对象并不归调用者所有
归调用者所有的意思是:调用上述四种方法的那段代码要负责释放方法所返回的对象。也就是说,这些对象的保留计数是正值,而调用了这四种方法的那段代码要将其中一次保留操作抵消掉。如果还有其他对象保留此对象,并对其调用了 autorelease,那么保留计数的值可能比1大,这也是 retainCount 方法不太有用的原因之一(参见第36条)。
来看一下下面这两个方法:
+ (ECPerson*) newPerson {
EOCPerson *person = [ [EOCPerson alloc] init];
return person;
/ **
* The method name begins with 'new', and since 'person'
* already has an unbalanced +1 retain count from the
* 'alloc', no retains, releases, or autoreleases are
* required when returning.
* /
}
+ (EOCPerson*) somePerson