内存管理-弱引用管理

2019-07-16  本文已影响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

上一篇下一篇

猜你喜欢

热点阅读