您的位置:首页 > 移动开发 > Objective-C

Objective-C 基础知识之 (十六):内存管理原则一

2015-09-25 20:12 495 查看
内存管理

OC中的内存管理机制:引用计数
每个对象都有引用计数。理论上:当对象的引用计数为0时,系统会自动调用方法,销毁对象,回收内存。
在开发中,存在多个指针操作同一个对象。如果需要使用对象,不想出现对象提前被销毁的情况,需要增加这个对象的引用计数。
如果不再需要使用对象,减少相应的引用计数。

引用计数加1的实现:

alloc 引用计数加1 0 -> 1
Person * p =[[Person alloc] init]; //1
NSLog(@"%lu",p.retainCount);
Retain.count计算对象的引用次数,返回值NSUinteger。

retain 引用计数加1 在原有的基础上增加
[p retain]; // 2
NSLog(@"%lu", p.retainCount);

copy 引用计数加1
被拷贝对象的引用计数不变,新创建的对象的引用计数从0增加为1。

引用计数减1的实现:

release 引用计数减1 在原有的基础上减少
[p release];
NSLog(@"%lu",p.retainCount); // 1

[p release]; // 0
此时,系统销毁对象,回收内存。
指针p被称为野指针。不应该再使用指针p操作原对象调用方法
NSLog(@"%lu",p.retainCount);

autorelease 引用计数减1 在未来的某个时刻减1
p = nil; // 空指针

如果想安全使用对象,可以通过对象调用retain方法,增加对象的引用计数。 持有(拥有)对象。
当不再需要使用对象时,要通过对象调用release方法,减少对象的引用计数。
在一段代码内,保证引用计数的增加和减少平衡,保证对象的引用计数最终可以减到0.

对象的引用计数增减不平衡,会造成的情况:内存泄露、野指针异常。
内存泄露:增加的次数 > 减少的次数
Person * p =[[Person alloc]init]; // 1
[p retain]; // 2
[p release];// 1
当main函数执行结束后,指针p被销毁,无法再通过指针找到对象,对象无法被销毁,内存空间无法释放

野指针异常:增加的次数 < 减少的次数
Person * p =[[Person alloc]init]; // 1
[p release];// 0 这句话执行结束后,对象已经被销毁.

p = nil; 在OC中将指针置为nil,可以避免野指针。
[p release];// -1 这句话中的p是野指针,过度释放。

当对象的引用计数应该减为0时,对象自动调用dealloc方法,销毁对象,释放内存。
- (void)dealloc
{
NSLog(@"Person对象将要被销毁");

[super dealloc]; //这句话写在最后。
}

Autorelease
在MRC下使用NSAutoreleasePool类

创建自动释放池
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

两句话之间的位置,属于自动释放池内部
Person * p = [[Person alloc] init];
[p retain];
如果对象P在自动释放池pool内部,调用autorelease方法,那么自动释放池会记录对象将要调用release方法的信息。
对象在自动释放池内部调用N次autorelease方法。那么,自动释放池会记录N次。
[p autorelease];
[p autorelease];
NSLog(@"自动释放池未被销毁:%lu", p.retainCount);

销毁自动释放池
[pool release];

autorelease什么时候实现引用计数减1?
管理这个对象的自动释放池被销毁时,在自动释放池内部调用autorelease方法的对象,全部会执行一次release方法
NSLog(@"自动释放池未被销毁:%lu", p.retainCount);
自动释放池销毁方法 [pool release] 或 [pool drain]

MRC、ARC 下的autorelease
@autoreleasepool

Person * p =[[Person alloc] init];
[p retain];
NSLog(@"%lu",p.retainCount);

@autoreleasepool {
自动释放池内部
[p autorelease];
NSLog(@"自动释放池未被销毁 %lu", p.retainCount);
}
NSLog(@"自动释放池被销毁 %lu", p.retainCount);
自动释放池可以自己创建,也可以是系统的方法实现内部创建
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: