您的位置:首页 > 大数据 > 人工智能

深入解析alloc/retain/release/dealloc实现

2015-07-22 09:08 387 查看
首先通过GNUstep上得源代码来叙述各个函数的实现(GNUstep是Cocoa框架的互换框架,二者的行为和实现方式非常相似)

GNUstep源代码中NSObject类的alloc方法:

id = obj = [NSObject alloc];

/**********************************/

+(id) alloc{

return [self allocWithZone : NSDefaultMallocZone()];

}

+(id) allocWithZone:(NSZone *) z{

return NSAllocateObject(self,0,z);

}

//NSZone是为了防止内存碎片化而引入的结构,对内存分配的区域本身进行多重画管理

NSAllocateObject函数如下:

struct obj_layout{

NSUInteger retained;

}

inline id NSAllocateObject(Class aClass,NSUInteger extraBytes,NSZone *zone){

int size =
计算容纳对象所需的内存;

id new  = NSZoneMalloc(Zone ,size);

memset(new ,0 ,size);

new  = (id) &((struct obj_layout *) new)[1];

}

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

/**************************/

-(NSUInteger) retainCount{

return NSExtraRefCount(self) + 1;

}

inline NSUInteger NSExtraRefCount(id anObject){

return ((struct obj_layout *) anObject)[-1].retained;

//由对象寻址找到对象内存头部,从而访问其中的retained变量

}

/***************************/

-(id) retain{

NSInCrementExtraRefCount(self);

return self;

}

inline void NSInCrementExtraRefCount(id anObject){

if((( struct obj_layout *) anObject)[-1].retained == UINT_MAX - 1){

[NSException raise:NSInternalInconsistencyException format:@“NSIncrementExtraRefCount()ask to increment too far”];

(( struct obj_layout *)anObject) [-1].retained++;

}

}

/********************************/

-(void) release{

if(NSDecrementExtraREfCountWasZero(self))

[self dealloc];

}

BOOL NSDecrementExtraREfCountWasZero(id anObject){

if((struct obj_layout *) anObject)[-1].retained == 0){

return YES;

}else{

(struct obj_layout *) anObject)[-1].retained—;

return NO;

}

}

/**********************************/

-(void ) dealloc{

NSDeallocateObject(self);

}

inline void NSDeallocateObject(id anObject){

struct obj_layout *o = &((struct obj_layout *) anObject)[-1];

free(o);

}

以上就是GNUstep中的实现

//////////////////////////////////////////////////////////////////////////

苹果的实现

通过在NSObject类的alloc类方法上设置断点,查看其执行的函数为:

+alloc

+allocWithZone

class_createInstance

calloc



各个方法都调用了_CFDoExternRefOperation函数

/************************************************/

int  _CFDoExternRefOperation(uintptr_t op,id obj){

CFBasicHashRef table =
取得对象所对应的散列表(obj);

int count;

int count;

    switch (op) {

    case OPERATION_retainCount:

     count = CFBasicHashGetCountOfKey(table, obj);

    return count;

     case OPERATION_retain:

    CFBasicHashAddValue(table, obj);

    return obj;

     case OPERATION_release:

    count = CFBasicHashRemoveValue(table, obj);

     return 0 == count;

    }

}

何为散列表

散列表(也叫哈希表)是一种查找算法,与链表、树等算法不同的是,散列表算法在查找时不需要进行一系列和关键字(关键字是数据元素中某个数据项的值,用以标识一个数据元素)的比较操作。

    散列表算法希望能尽量做到不经过任何比较,通过一次存取就能得到所查找的数据元素,因而必须要在数据元素的存储位置和它的关键字(可用key表示)之间建立一个确定的对应关系,使每个关键字和散列表中一个唯一的存储位置相对应。因此在查找时,只要根据这个对应关系找到给定关键字在散列表中的位置即可。这种对应关系被称为散列函数(可用h(key)表示)。

    根据设定的散列函数h(key)和处理冲突的方法将一组关键字key映像到一个有限的连续的地址区间上,并以关键字在地址区间中的像作为数据元素在表中的存储位置,这种表便被称为散列表,这一映像过程称为散列,所得存储位置称为散列地址。

由上可知苹果是将计数器保存在引用记数表的记录中

好处:

(1) 对象用内存块的分配无需考虑内存头部

(2) 引用计数表个记录中存有内存块地址,可追溯到个内存块.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息