在之前的介绍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绑定的属性);
- 移除散列表中存储的弱引用指针和对象引用计数.