iOS NSObject 释放流程

相关结构体介绍:

# if __arm64__
#   define ISA_MASK        0x0000000ffffffff8ULL
#   define ISA_MAGIC_MASK  0x000003f000000001ULL
#   define ISA_MAGIC_VALUE 0x000001a000000001ULL
#   define ISA_BITFIELD                                                      \	// 是否指针,initIsa=NO,initClassIsa=maybe, initProtocolIsa=maybe
      uintptr_t nonpointer        : 1;                                       \
      uintptr_t has_assoc         : 1;  // 是否有关联属性                                     \
      uintptr_t has_cxx_dtor      : 1;  // 是否有c++相关的析构函数                                     \	// 地址
      uintptr_t shiftcls          : 33; /*MACH_VM_MAX_ADDRESS 0x1000000000*/ \
      uintptr_t magic             : 6;  // 模数 32位还是64位                                     \
      uintptr_t weakly_referenced : 1; // 弱引用表中是否有关它的                                     \
      uintptr_t deallocating      : 1; // 是否在释放                                      \
      uintptr_t has_sidetable_rc  : 1; // 使用sidetable计数                                      \
      uintptr_t extra_rc          : 19 // 引用计数
#   define RC_ONE   (1ULL<<45)
#   define RC_HALF  (1ULL<<18)
// 它是weak的哈希表,使用数组保存数据,对象地址哈希值与上mask得到索引,冲突时候向下移,并记录移动次数。内部大量使用这种结构,快速!
struct weak_table_t {
   
    weak_entry_t *weak_entries; // 弱引用对象数组
    size_t    num_entries; // 弱引用对象个数
    uintptr_t mask; // 容量-1
    uintptr_t max_hash_displacement;// 最大哈希值冲突偏移次数
};
struct weak_entry_t {
   
	// DisguisedPtr伪指针,让人不能直接读取值,referent对象地址数组,弱属性指针指向的对象,为什么是数组呢,后面发现calloc申请内存给它。out_of_line_ness就标记使用哪种结构体,为2的时候使用上面一种,一开始是0or3。设计为这样的结构是因为大部分弱指针比较少
    DisguisedPtr<objc_object> referent;
    union {
    
    /// 联合体,使用下面结构体之一。一开始使用下面的结构体,最大4个,大于等于使用上面的结构体,可以存储更多个。
        struct {
   
        //  weak属性指针
            weak_referrer_t *referrers;// 其实typedef DisguisedPtr<objc_object *> weak_referrer_t; DisguisedPtr是只有一个成员变量uintptr_t value的类,伪装保存的值。
            uintptr_t        out_of_line_ness : 2;// append_referrer的时候,之前已经存在,referrers个数大于等于指定大小(4)即标记为2。
            uintptr_t        num_refs : PTR_MINUS_2; // weak属性指针个数,占30or62位
            uintptr_t        mask;// 容量-1
            // 哈希冲突时候偏移次数,即哈希冲突时候索引加1的次数
            uintptr_t        max_hash_displacement;
        };
        struct {
   
            // out_of_line_ness field is low bits of inline_referrers[1]
            weak_referrer_t  inline_referrers[WEAK_INLINE_COUNT]; //WEAK_INLINE_COUNT = 4,大小跟上面一致
        };
    };
}

1、dealloc 调用 _objc_rootDealloc(self)

2、_objc_rootDealloc(self) 调用obj->rootDealloc();

3、rootDealloc 分两种情况:
1)、是nonpointer、没有被添加到弱引用表、没有c++相关的析构、没有sidetable的引用计数、没有。
2)、以上之一有。
情况1)直接freen(this)
情况2):object_dispose((id)this);

4、objc_destructInstance(obj); 没有释放内存 free(obj);最后才释放内存

5、有c++相关的析构object_cxxDestruct(obj);
有关关联属性 _object_remove_assocations(obj);
清空自己 obj->clearDeallocating();

6、object_cxxDestructFromClass
循环遍历自己一直往super,寻址析构函数,lookupMethodInClassAndLoadCache(cls, SEL_cxx_destruct);
然后调用。

7、_object_remove_assocations
从AssociationsManager的AssociationsHashMap中找到有关自己的AssociationsHashMap,拿到ObjectAssociationMap,从头遍历链表放到一个vector中,同时也从ObjectAssociationMap中删除,调用for_each,再次遍历vector,挨个调用ReleaseValue(),里面调用releaseValue,再调用objc_release,最后调用objc_msgSend发送SEL_release定义的宏方法。

8、clearDeallocating 分两种情况
1)nonpointer时候调用sidetable_clearDeallocating,从SideTable中的refcnts找到自己,然后调用weak_clear_no_lock,这个跟情况2)一样,最后从SideTable的refcnts调用erase移除自己。
2)调用clearDeallocating_slow,里面调用weak_clear_no_lock从弱引用表中删除,最后有has_sidetable_rc,则从SideTable的refcnts中移除自己。

9、weak_clear_no_lock
从SideTable找自己,调用的是weak_entry_for_referent

10、weak_entry_for_referent
SideTable的wek_entries数组下标找到自己的weak_entry_t,下标通过hash算法得到。哈希值与上mask得到索引。直接拿到弱引用对象weak_entry_t,比较referent是否等于自己,不等于索引加1,继续比较,如果都没有返回nil。循环遍历weak_entry_t的referrers,与自己相等则置为nil,调用weak_entry_remove(weak_table, entry)
hash算法:自己的地址右移4位 然后异或自己,得到的结果再诚意一个数值0x8a970be7488fda55,最后反转个位值再异或得到最后的哈希值,key ^= __builtin_bswap64(key);为什么这样做呢,利用全部位的值得到随机的哈希值。

11、weak_entry_remove(weak_table, entry);
free释放entry的referrers,都置为0,然后weak_table缩容处理weak_compact_maybe

12、weak_compact_maybe
旧容量>= 1024 且 旧容量、16 >= weak_table的entry个数,则缩容。
容量为原来的8分之一。把旧的数组数据搬到新的数组里面。

- (void)dealloc {
   
    _objc_rootDealloc(self);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值