在之前的介紹isa_t時,曾經提起isa中存儲了has_cxx_dtor信息,如果對象不包含該標誌,釋放時速度會更快一些.這說明在對象釋放時並不是簡單的進行對象空間的釋放,應該會還有一些額外的輔助操作.
使用objc4-756.2源代碼進行說明.
對象釋放過程
在對象的釋放過程中會調用系統或者自定義實現的deallo函數,就從這裏開始.
dealloc
// Replaced by NSZombies
- (void)dealloc {
_objc_rootDealloc(self);
}
_objc_rootDealloc
void
_objc_rootDealloc(id obj)
{
assert(obj);
obj->rootDealloc();
}
objc->rootDealloc
- 若當前對象是標籤指針則直接返回;
- 若當前對象使用nonpointer計數且不包含弱引用指針關聯對象析構函數以及全局散列表中不包含對象引用計數數據時,直接釋放對象空間;否則繼續執行(從這裏可以大致看出對象釋放時最起碼要處理指向對象的弱指針引用,動態關聯到對象的屬性,對象的析構函數以及存儲在全局散列表中引用計數等);
- 執行object_dispose.
-
inline void objc_object::rootDealloc() { //如果是標籤指針則不進行管理(因爲標籤指針不指向任何對象,只是一個保存了標籤和數據的"假指針") if (isTaggedPointer()) return; // fixme necessary? //如果使用nonpointer計數且不包含弱引用指針關聯對象析構函數以及散列表中不包含引用計數時直接釋放 if (fastpath(isa.nonpointer && !isa.weakly_referenced && !isa.has_assoc && !isa.has_cxx_dtor && !isa.has_sidetable_rc)) { assert(!sidetable_present()); free(this); } else { //調用objc_dispose object_dispose((id)this); } }
object_dispose
-
object_dispose(id obj) { //若obj不存在直接返回 if (!obj) return nil; //調用objc_destructInstance objc_destructInstance(obj); //釋放對象空間 free(obj); return nil; }
objc_destructInstance
-
/*********************************************************************** * objc_destructInstance * Destroys an instance without freeing memory. * Calls C++ destructors. * Removes associative references. * Returns `obj`. Does nothing if `obj` is nil. * CoreFoundation and other clients do call this under GC. **********************************************************************/ void *objc_destructInstance(id obj) { if (obj) { Class isa = obj->getIsa(); if (isa->hasCxxDtor()) { object_cxxDestruct(obj); } if (isa->instancesHaveAssociatedObjects()) { _object_remove_assocations(obj); } objc_clear_deallocating(obj); } return obj; }
- 判斷是否具有析構函數,是則執行析構函數;
-
/*********************************************************************** * object_cxxDestruct. * Call C++ destructors on obj, if any. * Uses methodListLock and cacheUpdateLock. The caller must hold neither. **********************************************************************/ void object_cxxDestruct(id obj) { if (!obj) return; //如果是標籤指針則直接返回 if (obj->isTaggedPointer()) return; //遍歷繼承鏈並執行析構函數 object_cxxDestructFromClass(obj, obj->ISA()); }
- object_cxxDestructFromClass:遍歷繼承鏈查找父類析構函數並執行.
-
/*********************************************************************** * object_cxxDestructFromClass. * Call C++ destructors on obj, starting with cls's * dtor method (if any) followed by superclasses' dtors (if any), * stopping at cls's dtor (if any). * Uses methodListLock and cacheUpdateLock. The caller must hold neither. **********************************************************************/ static void object_cxxDestructFromClass(id obj, Class cls) { void (*dtor)(id); //調用當前類的析構函數,然後遍歷父類查找父類析構函數並調用 for ( ; cls; cls = cls->superclass) { //如果當前類不存在析構函數則直接返回 if (!cls->hasCxxDtor()) return; //查找當前類的析構函數 dtor = (void(*)(id)) lookupMethodInClassAndLoadCache(cls, SEL_cxx_destruct); //判斷是否查找到析構函數 if (dtor != (void(*)(id))_objc_msgForward_impcache) { //獲取全局環境變量 if (PrintCxxCtors) { _objc_inform("CXX: calling C++ destructors for class %s", cls->nameForLogging()); } //執行析構函數 (*dtor)(obj); } } }
- 判斷是否包含了關聯屬性,是則移除關聯屬性;
-
void _object_remove_assocations(id object) { //將操作進行封裝 vector< ObjcAssociation,ObjcAllocator<ObjcAssociation> > elements; { //全局管理對象 AssociationsManager manager; //獲取AssociationsHashMap對象引用 AssociationsHashMap &associations(manager.associations()); //關聯對象個數爲0 if (associations.size() == 0) return; //進行哈希運算 disguised_ptr_t disguised_object = DISGUISE(object); //使用迭代器查找關聯屬性 AssociationsHashMap::iterator i = associations.find(disguised_object); if (i != associations.end()) { // 拷貝需要移除的所有關聯屬性 ObjectAssociationMap *refs = i->second; //遍歷所有關聯屬性 for (ObjectAssociationMap::iterator j = refs->begin(), end = refs->end(); j != end; ++j) { //輸出關聯屬性 elements.push_back(j->second); } // 刪除輔助表 delete refs; associations.erase(i); } } //執行封裝之後的操作 for_each(elements.begin(), elements.end(), ReleaseValue()); }
- 執行obj->clearDeallocating
obj->clearDeallocating
inline void
objc_object::clearDeallocating()
{
//判斷當前對象是否支持nonpointer,否則直接執行sidetable_clearDeallocating
if (slowpath(!isa.nonpointer)) {
// Slow path for raw pointer isa.
sidetable_clearDeallocating();
}
else if (slowpath(isa.weakly_referenced || isa.has_sidetable_rc)) {
//若當前對象isa中包含weakly_referenced || has_sidetable_rc
clearDeallocating_slow();
}
assert(!sidetable_present());
}
- 判斷當前對象是否支持nonpointer,否則直接執行sidetable_clearDeallocating:
-
void objc_object::sidetable_clearDeallocating() { SideTable& table = SideTables()[this]; //添加線程鎖 table.lock(); RefcountMap::iterator it = table.refcnts.find(this); if (it != table.refcnts.end()) { //清除弱引用表 if (it->second & SIDE_TABLE_WEAKLY_REFERENCED) { weak_clear_no_lock(&table.weak_table, (id)this); } //清除引用計數 table.refcnts.erase(it); } table.unlock(); }
-
weak_clear_no_lock
-
判斷弱引用表中是否存在referent對應的weak_entry_t結構:否,則說明該對象不存在弱引用指針直接返回;
-
判斷弱引用表使用靜態數組存儲還是使用離線存儲,並獲取存儲空間首地址referrers和弱引用指針個數count;
-
遍歷存儲空間查找指向referent的弱引用指針並置空.
-
-
/** * 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); 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; } //遍歷弱引用數組逐個置空指向referent的弱引用指針 for (size_t i = 0; i < count; ++i) { objc_object **referrer = referrers[i]; if (referrer) { //當前弱指針指向對象referent if (*referrer == referent) { //置空弱引用指針 *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(); } } } //從weak_table中移除entry weak_entry_remove(weak_table, entry); }
-
- 支持nonpointer判斷isa中是否包含弱引用指針標誌weakly_referenced或者包含引用計數存儲在散列表中的標誌has_sidetable_rc:是則執行clearDeallocating_slow清除散列表中的數據.
-
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(); }
總結
綜上所述,在對象釋放的過程中至少做了這麼幾件事:
- 調用對象析構函數;
- 移除對象上動態綁定屬性(使用objc_setAssociatedObject綁定的屬性);
- 移除散列表中存儲的弱引用指針和對象引用計數.