iOS中的ARC---内存管理的思考方式

本文参考:《objective-c高级编程》

一、引用计数式内存管理的思考方式

①自己生成的对象,自己持有
②非自己生成的对象,自己也能持有
③不再需要自己持有的对象时,释放
④非自己持有的对象,无法释放

以下逐一做讲解:

①自己生成的对象,自己持有

/* alloc
 * new
 * copy
 * mutableCopy
*/
//自己生成,并持有对象
id obj1 = [[NSObject alloc] init];
id obj2 = [NSObject new];

②非自己生成的对象,自己也能持有

//取得非自己生成并持有的对象,obj不持有该数组
id obj = [NSMutableArray array];

//obj持有数组
[obj retain];

③不再需要自己持有的对象时,释放

id obj1 = [[NSObject alloc] init];
[obj release];

④非自己持有的对象,无法释放

id obj1 = [[NSObject alloc] init];
[obj release];
[obj release]; //wrong

⑤autorelease

//如果要用某个方法生成对象,并将其返还给该方法的调用方。
- (id)allocObject {
    //自己生成并持有对象
    id obj = [[NSObject alloc] init];
    return obj;
}

//注意命名规则,不能加alloc
- (id)Object {
    //自己生成并持有对象
    id obj = [[NSObject alloc] init];

    //取得的对象存在,但自己不持有对象。autorelease使对象在超出指定的生存范围时能够自动并正确的释放(调用release方法)
    [obj autorelease];

    return obj;
}

使用以上两种方式的区别:

{
    [obj allocObject];
}

{
    [obj object];
    [obj retain];
}

二、alloc/retain/release/dealloc的实现

NSObject类的Foundation框架没有公开。此处是使用GNUstep来参考的(它是Cocoa框架的互换框架)

1.先看看GNUstep内部的实现(简单说明):
①alloc:
alloc—>allocWithZone—>NSAllocateObject

NSAllocateObject:(通过NSZoneMalloc函数分配存放对象所需的内存空间,之后将该内存空间置0,最后返回作为对象而使用的指针)

NSZone:为了防止内存碎片化而引入的结构,对内存分配的区域本身进行多重化管理,根据使用对象的目的、对象的大小分配内存,提供了使用效率。

结论:
alloc类方法中,用一个结构体中的NSUInteger retained来保存引用计数,并将其写入对象内存的头部。

②retain/release

③dealloc
dealloc—>NSDeallocateObject(self)

2.苹果的实现
苹果内部不是把retain值写在对象的头部,它是采用引用计数表来管理引用计数,两者对比一下:
①写在头部:
a)少量代码完成
b)能够统一管理引用计数和对象使用的内存块

②引用计数表
a)分配内存时无需考虑内存块头部
b)表中存有内存块地址,可以从各个记录追溯到各个对象的内存块(这个很好,当出现故障使内存块损坏时,可以通过表来确认内存块的位置)

三、详细解释autorelease

1.首先看看C语言:

{
    int a;
}
//超出{}作用域后,变量a被废弃,不可访问

2.OC中类似作用域的东西:NSAutoreleasePool
作用:相当于{},废弃NSAutoreleasePool对象时,调用它内部的对象的release方法

    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
    id obj = [[NSObject alloc] init];
    [obj autorelease];
    [pool drain];

PS:大量的创建NSAutoreleasePool对象,但是不废弃它,它内部的对象就不会被释放。有时会造成内存不足的现象(例如,读入大量图片的同时改变尺寸)

3.autorelease的实现
①先看看GUNstep如何实现的

autorelease实例方法的本质就是调用NSAutoreleasePool对象的addObject方法

-(id) autorelease {
    [NSAutoreleasePool addObject:self];
}

//GNUstep中使用的是连接链表,就好比在NSMutableArray中添加一个对象
-(void) addObject:(id) obj {
    [array addObject:obj];
}

//当调用drain方法时
[pool drain];

-(void) drain {
    [self dealloc];
}
-(void) dealloc {
    [self emptyPool];
    [array release];
}
-(void) emptyPool {
    [obj release];
}

②苹果的实现和以上原理相同,此处不讲了。

PS:

//发生异常
//无论哪个对象调用autorelease,实际上都是调用NSObject类的autorelease实例方法。但是对于NSAutoreleasepool,这个实例方法已经被它重载,运行时就会出错。
NSAutoreleasepool *pool = [[NSAutoreleasepool alloc] init];
[pool autorelease];
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值