美文网首页
iOS中weak的实现原理

iOS中weak的实现原理

作者: 土豆骑士 | 来源:发表于2020-06-13 12:39 被阅读0次

1:weak的实现原理

answer one:
通过weak_store将weak对象,以[key:value]的形式存储在sidetable中,以weak属性所指向的地址作为key,weak对象作为value。

answer two:
Runtime会维护一个weak表(弱引用表),用于维护对象的所有weak指针。
weak表是一个哈希表,其key为weak对象的指针,value为weak指针的地址数组。
具体如下:
1:初始化时,Runtime会调用objc_initWeak函数,初始化一个新的weak指针指向对象的地址。
2:添加引用时 objc_initWeak函数会调用objc_storeWeak()函数,更新指针指向,创建对应的弱引用表。
3:释放dealloc时,调用clearDeallocating函数,该函数首先会根据对象地址获取所有的weak指针地址的数组,遍历这个数组把其中的数据置为nil,最后把这个entry从weak表中删除,最后清理对象的记录。

代码 原理 概图

2:探索

SideTable

struct SideTable {
    spinlock_t slock;       //锁,互斥锁
    RefcountMap refcnts;    //引用计数表
    weak_table_t weak_table;//弱引用表

    SideTable() {
        memset(&weak_table, 0, sizeof(weak_table));
    }
...
}

weak_table_t: 全局弱引用表。将对象id存储为键,将weak_entry_t结构体存储为键的值。

/**
 * The global weak references table. Stores object ids as keys,
 * and weak_entry_t structs as their values.
 */
struct weak_table_t {//全局弱引用表。将对象id存储为键,将weak_entry_t结构体存储为键的值。
    weak_entry_t *weak_entries;     //弱 entries 一个数组吧?
    size_t    num_entries;          //entry num
    uintptr_t mask;                 //面具 掩码
    uintptr_t max_hash_displacement;
};

objc_initWeak: 初始化 storeWeak(): 更新weak变量

id objc_initWeak(id *location, id newObj) {
    if (!newObj) {
        *location = nil;
        return nil;
    }

    return storeWeak<DontHaveOld, DoHaveNew, DoCrashIfDeallocating>
        (location, (objc_object*)newObj);
}

static id storeWeak(id *location, objc_object *newObj) {
    ......
    // Clean up old value, if any.
    if (haveOld) { // Unregister an already-registered weak reference
        weak_unregister_no_lock(&oldTable->weak_table, oldObj, location);
    }

    // Assign new value, if any.
    if (haveNew) {
        newObj = (objc_object *)
            weak_register_no_lock(&newTable->weak_table, (id)newObj, location, 
                                  crashIfDeallocating);
        // weak_register_no_lock returns nil if weak store should be rejected

        // Set is-weakly-referenced bit in refcount table.
        if (newObj  &&  !newObj->isTaggedPointer()) {
            newObj->setWeaklyReferenced_nolock();
        }

        // Do not set *location anywhere else. That would introduce a race.
        *location = (id)newObj;
    }
    else {
        // No new value. The storage is not changed.
    }
    
    SideTable::unlockTwo<haveOld, haveNew>(oldTable, newTable);

    return (id)newObj;
}

weak_register_no_lock

//Registers a new (object, weak pointer) pair. Creates a new weak object entry if it does not exist.
id weak_register_no_lock(weak_table_t *weak_table, id referent_id, 
                      id *referrer_id, bool crashIfDeallocating) {
    objc_object *referent = (objc_object *)referent_id;
    objc_object **referrer = (objc_object **)referrer_id;

    if (!referent  ||  referent->isTaggedPointer()) return referent_id;

    // ensure that the referenced object is viable
    bool deallocating;
    ....
    // now remember it and where it is being stored
    weak_entry_t *entry;
    if ((entry = weak_entry_for_referent(weak_table, referent))) {//找到weak_table中的entry
        append_referrer(entry, referrer);                         //add
    } 
    else {
        weak_entry_t new_entry(referent, referrer);//创建新的 weak_entry_t
        weak_grow_maybe(weak_table);               //扩容
        weak_entry_insert(weak_table, &new_entry); //在weak_table中 插入 新的entry
    }

    // Do not set *referrer. objc_storeWeak() requires that the 
    // value not change.

    return referent_id;
}

释放一个weak对象

释放weak对象,函数调用过程
- (void)dealloc {
    _objc_rootDealloc(self);
}

void _objc_rootDealloc(id obj) {
    ASSERT(obj);

    obj->rootDealloc();
}

inline void objc_object::rootDealloc() {
    if (isTaggedPointer()) return;  // fixme necessary?

    if (fastpath(isa.nonpointer  &&  
                 !isa.weakly_referenced  &&  
                 !isa.has_assoc  &&  
                 !isa.has_cxx_dtor  &&  
                 !isa.has_sidetable_rc)) {
        assert(!sidetable_present());
        free(this);
    } else {
        object_dispose((id)this);
    }
}
id object_dispose(id obj) {
    if (!obj) return nil;
    // weak
    // cxx
    // 关联对象
    // ISA 64
    objc_destructInstance(obj);    
    free(obj);

    return nil;
}
void *objc_destructInstance(id obj)  {
    if (obj) {
        // Read all of the flags at once for performance.
        bool cxx = obj->hasCxxDtor();
        bool assoc = obj->hasAssociatedObjects();

        // This order is important.
        if (cxx) object_cxxDestruct(obj);
        if (assoc) _object_remove_assocations(obj);
        obj->clearDeallocating();
    }

    return obj;
}

inline void  objc_object::clearDeallocating() {
    if (slowpath(!isa.nonpointer)) {
        // Slow path for raw pointer isa.
        sidetable_clearDeallocating();
    }
    else if (slowpath(isa.weakly_referenced  ||  isa.has_sidetable_rc)) {
        // Slow path for non-pointer isa with weak refs and/or side table data.
        clearDeallocating_slow();
    }

    assert(!sidetable_present());
}
NEVER_INLINE void objc_object::clearDeallocating_slow() {
    ASSERT(isa.nonpointer  &&  (isa.weakly_referenced || isa.has_sidetable_rc));

    SideTable& table = SideTables()[this];
    table.lock();
    if (isa.weakly_referenced) {//有弱引用对象
        weak_clear_no_lock(&table.weak_table, (id)this);//清理弱引用表
    }
    if (isa.has_sidetable_rc) { //有引用计数表
        table.refcnts.erase(this);//清理引用计数表
    }
    table.unlock();
}

/** 
 * Called by dealloc; nils out all weak pointers that point to the 
 * provided object so that they can no longer be used.
 * 
 * @param weak_table   弱表
 * @param referent The object being deallocated. 正要收回的对象
 */
void 
weak_clear_no_lock(weak_table_t *weak_table, id referent_id) 
{
    objc_object *referent = (objc_object *)referent_id;

    weak_entry_t *entry = weak_entry_for_referent(weak_table, referent);//从哈希表中找出对应的weak entry。
    if (entry == nil) {
        /// XXX shouldn't happen, but does with mismatched CF/objc
        //printf("XXX no entry for clear deallocating %p\n", referent);
        return;
    }

    // zero out references
    weak_referrer_t *referrers;
    size_t count;
    
    if (entry->out_of_line()) {
        referrers = entry->referrers;
        count = TABLE_SIZE(entry);
    } 
    else {
        referrers = entry->inline_referrers;
        count = WEAK_INLINE_COUNT;
    }
    
    for (size_t i = 0; i < count; ++i) {
        objc_object **referrer = referrers[i];
        if (referrer) {
            if (*referrer == referent) {
                *referrer = nil;  //找到referrer 置为nil
            }
            else if (*referrer) {
                _objc_inform("__weak variable at %p holds %p instead of %p. "
                             "This is probably incorrect use of "
                             "objc_storeWeak() and objc_loadWeak(). "
                             "Break on objc_weak_error to debug.\n", 
                             referrer, (void*)*referrer, (void*)referent);
                objc_weak_error();
            }
        }
    }
    //Remove entry from the zone's table of weak references.
    weak_entry_remove(weak_table, entry);//从区域的弱引用表中删除条目。
}

总结:当释放,dealloc时,调用clearDeallocating函数,该函数首先会根据对象地址获取所有的weak指针地址的数组,遍历这个数组把其中的数据置为nil,最后把这个entry从weak表中删除,最后清理对象的记录。

相关文章

  • iOS底层原理:weak的实现原理

    iOS底层原理:weak的实现原理iOS底层原理:weak的实现原理

  • iOS weak 底层实现原理(二):objc-weak 函数列

    前言 为了全面透彻的分析 weak 的实现原理,前面 iOS weak 底层实现原理(一):SideTable|s...

  • iOS 中 weak 实现原理

    weak 的作用 weak 关键字的作用弱引用,所引用对象的计数器不会加一,并在引用对象被释放的时候自动被设置为 ...

  • iOS 中 weak 的实现原理

    开头 本文是看了 iOS 底层解析weak的实现原理(包含weak对象的初始化,引用,释放的分析) 一文后,为了加...

  • iOS中weak的实现原理

    1:weak的实现原理 answer one:通过weak_store将weak对象,以[key:value]的形...

  • iOS weak实现原理

    我们日常开发中经常是使用weak关键字来解决循环引用的问题,原因是被weak引用的对象它的引用计数不会增加,而且在...

  • iOS中Hash的应用分析

    一、下图只是列出了部分知识点(Hash在iOS中的应用分析整理) 1.1、关联对象的实现原理: 1.2、weak的...

  • iOS weak的实现原理

    1.weak简述 weak表其实是一个hash表,Key是所指对象的地址,Value是weak指针的地址数组,we...

  • iOS weak的实现原理

  • weak实现原理

    平时开发中我们经常会用到weak,但是它的实现原理也许不是很清楚,今天就从源码来探究一下(weak实现原理源码链接...

网友评论

      本文标题:iOS中weak的实现原理

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