美文网首页
内存管理-弱引用管理

内存管理-弱引用管理

作者: 亲爱的大倩倩 | 来源:发表于2019-07-16 16:15 被阅读0次

    一个weak变量是怎样被添加到弱引用表当中的?
    可以通过弱引用对象进行哈希算法的计算,然后计算查找它对应的位置

    //使用__weak修饰的obj1变量指向obj,此时有了__weak弱引用指针
    id __weak obj1 = obj;
    
                   |  经过编译之后变成下面
    
    id obj1;
    objc_initWeak(&obj1,obj); //实际上是使用objc_initWeak函数(弱引用变量的地址,被修饰的对象)
    
    下面看下上面发生了什么过程

    objc_initWeak函数会调用storeWeak函数,然后调用weak_register_no_lock函数
    weak指针被添加到弱引用表的具体实现是在weak_register_no_lock中实现的

    源码分析
    //参数-弱引用变量,被弱引用的对象
    id
    objc_initWeak(id *location, id newObj)
    {
        if (!newObj) {
            *location = nil;
            return nil;
        }
        //老对象,新对象,在dealloc中是否可以被crash
        return storeWeak<false/*old*/, true/*new*/, true/*crash*/>
            (location, (objc_object*)newObj);
    }
    
    storeWeak(id *location, objc_object *newObj)
    {
        assert(HaveOld  ||  HaveNew);
        if (!HaveNew) assert(newObj == nil);
    
        Class previouslyInitializedClass = nil;
        id oldObj;
        SideTable *oldTable;
        SideTable *newTable;
    
     retry:
        if (HaveOld) {
            oldObj = *location;
            oldTable = &SideTables()[oldObj];
        } else {
            oldTable = nil;
        }
        if (HaveNew) {
            newTable = &SideTables()[newObj];
        } else {
            newTable = nil;
        }
    
        SideTable::lockTwo<HaveOld, HaveNew>(oldTable, newTable);
    
        if (HaveOld  &&  *location != oldObj) {
            SideTable::unlockTwo<HaveOld, HaveNew>(oldTable, newTable);
            goto retry;
        }
    
        if (HaveNew  &&  newObj) {
            //根据当前对象获取它的isa指针来找到它的类对象
            Class cls = newObj->getIsa();
            //对类对象进行一个是否已经初始化f过的判断
            if (cls != previouslyInitializedClass  &&  
                !((objc_class *)cls)->isInitialized()) 
            {
                SideTable::unlockTwo<HaveOld, HaveNew>(oldTable, newTable);
                _class_initialize(_class_getNonMetaClass(cls, (id)newObj));
    
    
                previouslyInitializedClass = cls;
    
                goto retry;
            }
        }
    
        if (HaveOld) {
            weak_unregister_no_lock(&oldTable->weak_table, oldObj, location);
        }
    
        if (HaveNew) {
            //weak_register_no_lock参数:从对象所属的side_table取出弱引用表的地址,被弱引用指向的原对象,弱引用指针,对象在废弃h过程中的标志位
            newObj = (objc_object *)weak_register_no_lock(&newTable->weak_table,
                                                          (id)newObj, location, 
                                                          CrashIfDeallocating);
            //如果新对象是有值得并且不是小对象的这种管理方式,就设置它为有弱引用的标志位
            if (newObj  &&  !newObj->isTaggedPointer()) {
                newObj->setWeaklyReferenced_nolock();
            }
    
            *location = (id)newObj;
        }
    
    //weak_table,原来的对象,弱引用指针,crashIfDeallocating
    weak_register_no_lock(weak_table_t *weak_table, id referent_id, 
                          id *referrer_id, bool crashIfDeallocating){
     //通过原对象指针去弱引用表中查找所对应的弱引用的数组entry
        if ((entry = weak_entry_for_referent(weak_table, referent))) {
            append_referrer(entry, referrer);
        } 
        else {
          //新创建弱引用数组,把对应位置置为nil
            weak_entry_t new_entry;
            new_entry.referent = referent;
            new_entry.out_of_line = 0;
            new_entry.inline_referrers[0] = referrer;
            for (size_t i = 1; i < WEAK_INLINE_COUNT; i++) {
                new_entry.inline_referrers[i] = nil;
            }
            
            weak_grow_maybe(weak_table);
           //把弱引用数组插到弱引用表的对应位置中
            weak_entry_insert(weak_table, &new_entry);
        }
    }
    
    static weak_entry_t *
    weak_entry_for_referent(weak_table_t *weak_table, objc_object *referent)
    {
        assert(referent);
        //通过弱引用表weak_table获取弱引用数组
        weak_entry_t *weak_entries = weak_table->weak_entries;
        if (!weak_entries) return nil;
        //然后通过原对象的指针地址,进行哈希算法计算,获取到对象在弱引用表中的对应索引位置
        size_t index = hash_pointer(referent) & weak_table->mask;
        size_t hash_displacement = 0;
        //哈希冲突算法,如果我们在对应位置获取到的对象,不是当前所要查找的对象,会根据冲突算法进行索引位置的移动,直到找到真正的对应对象的索引位置,再将查到的索引位置返回给调用方的数组当
        while (weak_table->weak_entries[index].referent != referent) {
            index = (index+1) & weak_table->mask;
            hash_displacement++;
            if (hash_displacement > weak_table->max_hash_displacement) {
                return nil;
            }
        }
        return &weak_table->weak_entries[index];
    }
    
    当一个对象被废弃之后,weak变量是如何处理的?

    会被自动置为nil



    在调dealloc后,经过一系列的调用,在内部最终会调用weak_clear_no_lock()函数,
    weak_clear_no_lock内部会根据当前对象指针查找弱引用表,把当前对象相对应的弱引用位置拿出来,是一个数组,然后遍历数组,遍历所有的弱引用指针,分别置为nil

    相关文章

      网友评论

          本文标题:内存管理-弱引用管理

          本文链接:https://www.haomeiwen.com/subject/wqxnkctx.html