zoukankan      html  css  js  c++  java
  • 深入解析alloc/retain/release/dealloc实现

    首先通过GNUstep上得源码来叙述各个函数的实现(GNUstepCocoa框架的互换框架,二者的行为和实现方式很相似)

    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;
        }

    }


    何为散列表

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

        散列表算法希望能尽量做到不经过不论什么比較。通过一次存取就能得到所查找的数据元素,因而必需要在数据元素的存储位置和它的keyword(可用key表示)之间建立一个确定的相应关系,使每一个keyword和散列表中一个唯一的存储位置相相应。因此在查找时,仅仅要依据这个相应关系找到给定keyword在散列表中的位置就可以。这样的相应关系被称为散列函数(可用h(key)表示)

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


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

    优点:

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

    (2) 引用计数表个记录中存有内存块地址,可追溯到个内存块.



  • 相关阅读:
    Java中的异常处理
    Java源码阅读Vector
    Java源码中遇到的一些问题(更新中)
    Java迭代器原理
    有趣的位运算-与或非
    有趣的位运算-移位运算
    为何要使用原码, 反码和补码?
    有趣的位运算-异或
    为什么实现Serializbale接口就能够进行序列化?
    死锁,活锁,饥饿
  • 原文地址:https://www.cnblogs.com/brucemengbm/p/6761113.html
Copyright © 2011-2022 走看看