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 的执行流程结束。
网友评论