美文网首页iOS
iOS - objc-weak

iOS - objc-weak

作者: ienos | 来源:发表于2021-04-10 16:25 被阅读0次

    Objective-C.OpenSource.GitHub

    一、 知识补充

    1. Tagged Pointer

    一个对象在 32 bit CPU 下占 4 byte,在 64bit CPU下是占 8 byte

    一个指针在 32 bit CPU下为 4 byte,在 64bit CPU下也是 8 byte

    Tagged Pointer 专门用来存储小的对象

    通常我们一个正常的对象需要通过指针寻址找到具体的值

    类似 NSNumber、NSdata 4 个字节已经够用了,所以在 64 bit 中引入 Tagged Pointer

    为了优化内存的使用,Tagged Pointer 即直接将值存储到指针中,8 byte 中 4 byte 存储值 4 byte 存储指针

    2. bit-mask

    在 objc-weak 中会看到诸如 index = w_hash_pointer(old_referrer) & (entry->mask) 的代码

    这里使用的是位屏蔽 bit-mask

    >> 例如通过 w_hash_pointer 散列计算得出 Value = 01010101

    然后 Mask = 00001111

    Mask    = 00001111b
    Value   = 01010101b
    Result  = 00000101b
    

    可以看出最后我们得到的结果总小于 Mask,意味着 Mask 用来作为 Value 最大值限制

    那么 Mask 就应该是 Result 的最大值

    二、数据结构

    image.png
    • referrer - weak pointer - 弱引用对象地址
    • referent - object pointer - 对象地址

    二、方法解析

    >> 1. hash 方法

    Function Description
    hash_pointer 散列对象指针
    w_hash_pointer 散列弱引用

    >> weak reference

    Function Description
    grow_refs_and_insert 扩展表的大小,并且插入新的 weak reference
    append_referrer 添加新的 weak reference 到 weak_entry
    remove_referrer 在 weak_entry 中移除 weak reference

    >> weak_table 表大小

    Function Description
    weak_resize 重新设置 weak_ table 表的大小,并重新存储 weak_entry
    weak_grow_maybe 如果 weak_table 中的 num_entries 超过表大小的 3/4 则 weak_resize 原来的两倍;若原先为 0 则默认为 64
    weak_compact_maybe 如果 weak_table 中的 num_entries 小于表大小的 1/16,或者表大小超过 1024 则 weak_resize 缩小为原来的 1/8

    >> weak_table 中对 weak_entry 的操作

    Function Description
    weak_entry_insert 在 weak_table 中插入 weak_entry
    weak_entry_remove 在 weak_table 中移除 weak_entry;并调用 weak_compact_maybe
    weak_entry_for_referent 在 weak_table 中找到某个对象的 weak_entry

    >> weak_table 的 weak reference 操作

    Function Description
    weak_unregister_no_lock 在 weak_table 中移除某个对象的对应 weak reference
    weak_register_no_lock 在 weak_table 中注册某个对象的对应 weak reference
    weak_clear_no_lock 清除某个对象对应的所有 weak reference
    weak_read_no_lock 获取某个 weak reference 对应的对象

    三、结构体解析

    1. SideTables

    保存的是关于所有对象的表,这里的表分为两级

    SideTables 是一个全局静态的表结构,表中保存的是 SideTable,key 对应的是对象的指针

    // alignas(StripedMap<SideTable>) 内存对齐方式
    alignas(StripedMap<SideTable>) static uint8_t 
        SideTableBuf[sizeof(StripedMap<SideTable>)];
    
    static void SideTableInit() {
        // 在 SideTableBuf 数组首地址中分配 StripedMap<SideTable>
        new (SideTableBuf) StripedMap<SideTable>();
    }
    
    // StripedMap<SideTable>& 引用 SideTables() 返回的值
    static StripedMap<SideTable>& SideTables() {
        // 强转 SideTableBuf 为 StripedMap<SideTable>* 指针
        return *reinterpret_cast<StripedMap<SideTable>*>(SideTableBuf);
    }
    

    2. StripedMap

    实际上也是散列表,一个大小为 8 的散列表

    template<typename T>
    class StripedMap {
    
        enum { CacheLineSize = 64 };
        enum { StripeCount = 8 };
    
        struct PaddedT {
            // 定义类型为 T 的变量 value,内存对齐 CacheLineSize
            T value alignas(CacheLineSize);
        };
    
        // 定义一个个数为 StripeCount 的 Padded 元素数组
        PaddedT array[StripeCount];
    
        static unsigned int indexForPointer(const void *p) {
            uintptr_t addr = reinterpret_cast<uintptr_t>(p);
            return ((addr >> 4) ^ (addr >> 9)) % StripeCount;
        }
    
     public:
        // stripedMap[p] 实质是一个表结构
        // index 其实是指针,通过散列计算获取对应 T 的实例对象
        T& operator[] (const void *p) { 
            return array[indexForPointer(p)].value; 
        }
        const T& operator[] (const void *p) const { 
            return const_cast<StripedMap<T>>(this)[p]; 
        }
    
    };
    

    3. SideTable

    一个 SideTable 对应一个 weak_table

    struct SideTable {
        spinlock_t slock;
        RefcountMap refcnts;
        weak_table_t weak_table;
    
        SideTable() {
            memset(&weak_table, 0, sizeof(weak_table));
        }
    
        ~SideTable() {
            _objc_fatal("Do not delete SideTable.");
        }
    
        void lock() { slock.lock(); }
        void unlock() { slock.unlock(); }
        bool trylock() { return slock.trylock(); }
    
        // Address-ordered lock discipline for a pair of side tables.
    
        template<bool HaveOld, bool HaveNew>
        static void lockTwo(SideTable *lock1, SideTable *lock2);
        template<bool HaveOld, bool HaveNew>
        static void unlockTwo(SideTable *lock1, SideTable *lock2);
    };
    

    4. weak_table

    存储 weak_entry 的结构体

    struct weak_table {
        // 存储 `weak_entry` 的数组,索引为 weak_entry->referent 的散列值
        weak_entry_t *weak_entries;
        // weak_entries 数组个数
        size_t  num_entries;
        // weak_entries 的最大索引,用于 bit-mask;当 mask 改变时需要重新计算 weak_entry->referent 散列值
        uintptr_t mask;
        // 最大散列值
        uintptr_t max_hash_displacement;
    };
    

    5. weak_entry

    weak_entryweak pointer 上存储分为两个部分:

    • inline_referrers - 定长数组
    • referrers - 动态数组,索引为 referrer 的散列值

    referrer 个数不超过 WEAK_INLINE_COUNT 4 时,使用 inline_referrers,否则使用 referrers

    #define WEAK_INLINE_COUNT 4
    struct weak_entry_t {
    
        // 源对象
        DisguisedPtr<objc_object> referent;
    
        union {
    
            /* 动态数组 */
            struct {
                weak_referrer_t *referrers;
                // 是否使用 referrers 的标志位,即是否超出 WEAK_INLINE_COUNT 个数
                uintptr_t        out_of_line : 1;
                // referrers 中元素个数
                uintptr_t        num_refs : PTR_MINUS_1;
                // referrers 的最大索引数量,用于 bit-mask;当 mask 改变时需要重新计算 referrer 散列值
                uintptr_t        mask;
                // 最大散列值
                uintptr_t        max_hash_displacement;
            };
    
            /* 定长数组 */
            struct {
                // out_of_line=0 is LSB of one of these (don't care which)
                weak_referrer_t  inline_referrers[WEAK_INLINE_COUNT];
            };
        };
    };
    

    6. weak_referrer

    对象指针的指针,即弱引用

    typedef objc_object ** weak_referrer_t;
    

    相关文章

      网友评论

        本文标题:iOS - objc-weak

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