1:weak的实现原理
answer one:
通过weak_store将weak对象,以[key:value]的形式存储在sidetable中,以weak属性所指向的地址作为key,weak对象作为value。
answer two:
Runtime会维护一个weak表(弱引用表),用于维护对象的所有weak指针。
weak表是一个哈希表,其key为weak对象的指针,value为weak指针的地址数组。
具体如下:
1:初始化时,Runtime会调用objc_initWeak函数,初始化一个新的weak指针指向对象的地址。
2:添加引用时 objc_initWeak函数会调用objc_storeWeak()函数,更新指针指向,创建对应的弱引用表。
3:释放dealloc时,调用clearDeallocating函数,该函数首先会根据对象地址获取所有的weak指针地址的数组,遍历这个数组把其中的数据置为nil,最后把这个entry从weak表中删除,最后清理对象的记录。

2:探索
SideTable
struct SideTable {
spinlock_t slock; //锁,互斥锁
RefcountMap refcnts; //引用计数表
weak_table_t weak_table;//弱引用表
SideTable() {
memset(&weak_table, 0, sizeof(weak_table));
}
...
}
weak_table_t: 全局弱引用表。将对象id存储为键,将weak_entry_t结构体存储为键的值。
/**
* The global weak references table. Stores object ids as keys,
* and weak_entry_t structs as their values.
*/
struct weak_table_t {//全局弱引用表。将对象id存储为键,将weak_entry_t结构体存储为键的值。
weak_entry_t *weak_entries; //弱 entries 一个数组吧?
size_t num_entries; //entry num
uintptr_t mask; //面具 掩码
uintptr_t max_hash_displacement;
};
objc_initWeak: 初始化 storeWeak(): 更新weak变量
id objc_initWeak(id *location, id newObj) {
if (!newObj) {
*location = nil;
return nil;
}
return storeWeak<DontHaveOld, DoHaveNew, DoCrashIfDeallocating>
(location, (objc_object*)newObj);
}
static id storeWeak(id *location, objc_object *newObj) {
......
// Clean up old value, if any.
if (haveOld) { // Unregister an already-registered weak reference
weak_unregister_no_lock(&oldTable->weak_table, oldObj, location);
}
// Assign new value, if any.
if (haveNew) {
newObj = (objc_object *)
weak_register_no_lock(&newTable->weak_table, (id)newObj, location,
crashIfDeallocating);
// weak_register_no_lock returns nil if weak store should be rejected
// Set is-weakly-referenced bit in refcount table.
if (newObj && !newObj->isTaggedPointer()) {
newObj->setWeaklyReferenced_nolock();
}
// Do not set *location anywhere else. That would introduce a race.
*location = (id)newObj;
}
else {
// No new value. The storage is not changed.
}
SideTable::unlockTwo<haveOld, haveNew>(oldTable, newTable);
return (id)newObj;
}
weak_register_no_lock
//Registers a new (object, weak pointer) pair. Creates a new weak object entry if it does not exist.
id weak_register_no_lock(weak_table_t *weak_table, id referent_id,
id *referrer_id, bool crashIfDeallocating) {
objc_object *referent = (objc_object *)referent_id;
objc_object **referrer = (objc_object **)referrer_id;
if (!referent || referent->isTaggedPointer()) return referent_id;
// ensure that the referenced object is viable
bool deallocating;
....
// now remember it and where it is being stored
weak_entry_t *entry;
if ((entry = weak_entry_for_referent(weak_table, referent))) {//找到weak_table中的entry
append_referrer(entry, referrer); //add
}
else {
weak_entry_t new_entry(referent, referrer);//创建新的 weak_entry_t
weak_grow_maybe(weak_table); //扩容
weak_entry_insert(weak_table, &new_entry); //在weak_table中 插入 新的entry
}
// Do not set *referrer. objc_storeWeak() requires that the
// value not change.
return referent_id;
}
释放一个weak对象

- (void)dealloc {
_objc_rootDealloc(self);
}
void _objc_rootDealloc(id obj) {
ASSERT(obj);
obj->rootDealloc();
}
inline void objc_object::rootDealloc() {
if (isTaggedPointer()) return; // fixme necessary?
if (fastpath(isa.nonpointer &&
!isa.weakly_referenced &&
!isa.has_assoc &&
!isa.has_cxx_dtor &&
!isa.has_sidetable_rc)) {
assert(!sidetable_present());
free(this);
} else {
object_dispose((id)this);
}
}
id object_dispose(id obj) {
if (!obj) return nil;
// weak
// cxx
// 关联对象
// ISA 64
objc_destructInstance(obj);
free(obj);
return nil;
}
void *objc_destructInstance(id obj) {
if (obj) {
// Read all of the flags at once for performance.
bool cxx = obj->hasCxxDtor();
bool assoc = obj->hasAssociatedObjects();
// This order is important.
if (cxx) object_cxxDestruct(obj);
if (assoc) _object_remove_assocations(obj);
obj->clearDeallocating();
}
return obj;
}
inline void objc_object::clearDeallocating() {
if (slowpath(!isa.nonpointer)) {
// Slow path for raw pointer isa.
sidetable_clearDeallocating();
}
else if (slowpath(isa.weakly_referenced || isa.has_sidetable_rc)) {
// Slow path for non-pointer isa with weak refs and/or side table data.
clearDeallocating_slow();
}
assert(!sidetable_present());
}
NEVER_INLINE void objc_object::clearDeallocating_slow() {
ASSERT(isa.nonpointer && (isa.weakly_referenced || isa.has_sidetable_rc));
SideTable& table = SideTables()[this];
table.lock();
if (isa.weakly_referenced) {//有弱引用对象
weak_clear_no_lock(&table.weak_table, (id)this);//清理弱引用表
}
if (isa.has_sidetable_rc) { //有引用计数表
table.refcnts.erase(this);//清理引用计数表
}
table.unlock();
}
/**
* Called by dealloc; nils out all weak pointers that point to the
* provided object so that they can no longer be used.
*
* @param weak_table 弱表
* @param referent The object being deallocated. 正要收回的对象
*/
void
weak_clear_no_lock(weak_table_t *weak_table, id referent_id)
{
objc_object *referent = (objc_object *)referent_id;
weak_entry_t *entry = weak_entry_for_referent(weak_table, referent);//从哈希表中找出对应的weak entry。
if (entry == nil) {
/// XXX shouldn't happen, but does with mismatched CF/objc
//printf("XXX no entry for clear deallocating %p\n", referent);
return;
}
// zero out references
weak_referrer_t *referrers;
size_t count;
if (entry->out_of_line()) {
referrers = entry->referrers;
count = TABLE_SIZE(entry);
}
else {
referrers = entry->inline_referrers;
count = WEAK_INLINE_COUNT;
}
for (size_t i = 0; i < count; ++i) {
objc_object **referrer = referrers[i];
if (referrer) {
if (*referrer == referent) {
*referrer = nil; //找到referrer 置为nil
}
else if (*referrer) {
_objc_inform("__weak variable at %p holds %p instead of %p. "
"This is probably incorrect use of "
"objc_storeWeak() and objc_loadWeak(). "
"Break on objc_weak_error to debug.\n",
referrer, (void*)*referrer, (void*)referent);
objc_weak_error();
}
}
}
//Remove entry from the zone's table of weak references.
weak_entry_remove(weak_table, entry);//从区域的弱引用表中删除条目。
}
总结:当释放,dealloc时,调用clearDeallocating函数,该函数首先会根据对象地址获取所有的weak指针地址的数组,遍历这个数组把其中的数据置为nil,最后把这个entry从weak表中删除,最后清理对象的记录。
网友评论