引用计数和weak原理

引用计数

为了管理所有对象的引用计数和weak指针,苹果创建了一个全局的SideTables,虽然名字后面有个"s"不过他其实是一个全局的Hash表,里面的内容装的都是SideTable结构体而已。它使用对象的内存地址当它的key

isa指针


Snip20200712_10.png

引用计数可以直接存储在优化过的isa指针中,也可能存储在SideTable中

struct SideTable {
    spinlock_t slock;
    RefcountMap refcnts;
    weak_table_t weak_table;
};

refcnts是一个存放着对象引用计数的散列表
获取引用计数

objc_object::rootRetainCount()
{
    if (isTaggedPointer()) return (uintptr_t)this;

    sidetable_lock();
    isa_t bits = LoadExclusive(&isa.bits);
    ClearExclusive(&isa.bits);
    if (bits.nonpointer) { // 优化过的isa
        uintptr_t rc = 1 + bits.extra_rc;
        if (bits.has_sidetable_rc) { // 存储在Sidetable中
            rc += sidetable_getExtraRC_nolock();
        }
        sidetable_unlock();
        return rc;
    }

    sidetable_unlock();
    return sidetable_retainCount();
}

objc_object::sidetable_getExtraRC_nolock()
{
    assert(isa.nonpointer);
   //SideTables是全局的Hash表
    SideTable& table = SideTables()[this]; // 对象self本身是key
    RefcountMap::iterator it = table.refcnts.find(this); // 对象self本身是key
    if (it == table.refcnts.end()) return 0;
    else return it->second >> SIDE_TABLE_RC_SHIFT;
}

dealloc调用流程

Snip20200712_11.png

weak指针销毁过程

dealloc 调用
clearDeallocating函数里面又调用clearDeallocating_slow

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

//SideTable中的weak_table_t 从下面的注释可以看出是全局的  

/**
 * The global weak references table. Stores object ids as keys,
 * and weak_entry_t structs as their values.
 */
struct weak_table_t {
    weak_entry_t *weak_entries;
    size_t    num_entries;
    uintptr_t mask;
    uintptr_t max_hash_displacement;
};
//其中weak_entry_t
 truct weak_entry_t {
    DisguisedPtr referent;
}

总结

weak是Runtime维护了一个hash(哈希)表(weak_table_t),用于存储指向某个对象的所有weak指针。weak表其实是一个hash(哈希)表,Key是所指对象的地址,Value是weak指针的地址(这个地址的值是所指对象指针的地址)数组。
1、初始化时:runtime会调用objc_initWeak函数,初始化一个新的weak指针指向对象的地址。
2、添加引用时:objc_initWeak函数会调用 storeWeak() 函数, storeWeak() 的作用是更新指针指向,创建对应的弱引用表。
3、释放时,调用clearDeallocating函数。clearDeallocating函数首先根据对象地址获取所有weak指针地址的数组,然后遍历这个数组把其中的数据设为nil,最后把这个entry从weak表中删除,最后清理对象的记录。

参考文章
链接:https://www.jianshu.com/p/ef6d9bf8fe59

你可能感兴趣的:(引用计数和weak原理)