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

来源:互联网 发布:北大青鸟java好学吗 编辑:程序博客网 时间:2024/06/05 06:05

本文参考:《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
原创粉丝点击