在之前的介绍isa_t时,曾经提起isa中存储了has_cxx_dtor信息,如果对象不包含该标志,释放时速度会更快一些.这说明在对象释放时并不是简单的进行对象空间的释放,应该会还有一些额外的辅助操作.
使用objc4-756.2源代码进行说明.
在对象的释放过程中会调用系统或者自定义实现的deallo函数,就从这里开始.
// Replaced by NSZombies
- (void)dealloc {
_objc_rootDealloc(self);
}
void
_objc_rootDealloc(id obj)
{
assert(obj);
obj->rootDealloc();
}
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(id obj)
{
//若obj不存在直接返回
if (!obj) return nil;
//调用objc_destructInstance
objc_destructInstance(obj);
//释放对象空间
free(obj);
return nil;
}
/***********************************************************************
* 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.
* 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 > 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());
}
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());
}
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);
}
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();
}
综上所述,在对象释放的过程中至少做了这么几件事: