美文网首页
weak,dealloc

weak,dealloc

作者: 云无心 | 来源:发表于2021-05-18 19:41 被阅读0次

    weak

    https://blog.csdn.net/u013378438/article/details/82790332

    Runtime 维护了一个 weak表,用于存储指向某个对象的所有weak指针。weak表 其实是一个 hash(哈希)表,Key 是所指对象的地址,Value是 weak指针 的地址(这个地址的值是所指对象指针的地址)数组。

    SideTables 有多个 SideTable hash值到 一个
    SideTable 内部有 slock 引用计数表,weak_table
    weak_table 内部有 weak_entries, hash 到 对应 weak_entry_t

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

    struct SideTable {
        // 保证原子操作的自旋锁
        spinlock_t slock;
        // 引用计数的 hash 表
        RefcountMap refcnts;
        // weak 引用全局 hash 表
        weak_table_t weak_table;
    }
    
    struct weak_table_t {
        // 保存了所有指向指定对象的 weak 指针
        weak_entry_t *weak_entries;
        // 存储空间
        size_t    num_entries;
        // 参与判断引用计数辅助量
        uintptr_t mask;
        // hash key 最大偏移值
        uintptr_t max_hash_displacement;
    };
    
    struct weak_entry_t {
        DisguisedPtr<objc_object> referent; // 被弱引用的对象
        
        // 引用该对象的对象列表,联合。 引用个数小于4,用inline_referrers数组。 用个数大于4,用动态数组weak_referrer_t *referrers
        union {
            struct {
                weak_referrer_t *referrers;                      // 弱引用该对象的对象指针地址的hash数组
                uintptr_t        out_of_line_ness : 2;           // 是否使用动态hash数组标记位
                uintptr_t        num_refs : PTR_MINUS_2;         // hash数组中的元素个数
                uintptr_t        mask;                           // hash数组长度-1,会参与hash计算。(注意,这里是hash数组的长度,而不是元素个数。比如,数组长度可能是64,而元素个数仅存了2个)素个数)。
                uintptr_t        max_hash_displacement;          // 可能会发生的hash冲突的最大次数,用于判断是否出现了逻辑错误(hash表中的冲突次数绝不会超过改值)
            };
            struct {
                // out_of_line_ness field is low bits of inline_referrers[1]
                weak_referrer_t  inline_referrers[WEAK_INLINE_COUNT];
            };
        };
    
        bool out_of_line() {
            return (out_of_line_ness == REFERRERS_OUT_OF_LINE);
        }
    
        weak_entry_t& operator=(const weak_entry_t& other) {
            memcpy(this, &other, sizeof(other));
            return *this;
        }
    
        weak_entry_t(objc_object *newReferent, objc_object **newReferrer)
            : referent(newReferent) // 构造方法,里面初始化了静态数组
        {
            inline_referrers[0] = newReferrer;
            for (int i = 1; i < WEAK_INLINE_COUNT; i++) {
                inline_referrers[i] = nil;
            }
        }
    };
    ————————————————
    

    dealloc

    1.首先调用 _objc_rootDealloc()
    2.接下来调用 rootDealloc()
    3.这时候会判断是否可以被释放,判断的依据主要有 5 个,判断是否有以上五种情况
     NONPointer_ISA weakly_reference  has_assoc has_cxx_dtor has_sidetable_rc
    4-1.如果有以上五中任意一种,将会调用 object_dispose()方法,做下一步的处理。
    4-2.如果没有之前五种情况的任意一种,则可以执行释放操作,C 函数的 free()。
    5.执行完毕。
    2.object_dispose() 调用流程。
     1.直接调用 objc_destructInstance()。
     2.之后调用 C 函数的 free()。

    3.objc_destructInstance() 调用流程
     1.先判断 hasCxxDtor,如果有 C++ 的相关内容,要调用 object_cxxDestruct() ,销毁 C++ 相关的内容。
     2.再判断hasAssocitatedObjects,如果有的话,要调用object_remove_associations(), 销毁关联对象的一系列操作。
     3.然后调用 clearDeallocating()。
     4.执行完毕。

    4.clearDeallocating() 调用流程。
     1.先执行 sideTable_clearDellocating()。
     2.再执行 weak_clear_no_lock,在这一步骤中,会将指向该对象的弱引用指针置为 nil。
     3.接下来执行 table.refcnts.eraser(),从引用计数表中擦除该对象的引用计数。
     4.至此为止,Dealloc 的执行流程结束。

    相关文章

      网友评论

          本文标题:weak,dealloc

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