相关结构体介绍:
# 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);
}