对象是怎么注销的?
2019-10-15 本文已影响0人
初灬终
dealloc ---> _objc_rootDealloc ---> rootDealloc
- (void)dealloc {
_objc_rootDealloc(self);
}
_objc_rootDealloc(id obj)
{
obj->rootDealloc();
}
inline void
objc_object::rootDealloc()
{
//对象是否为TaggedPointer,它不需要释放
if (isTaggedPointer()) return; // fixme necessary?
//对象是否为TaggedPointer
//对象是否有弱引用
//对象是否有关联对象
//对象是否有c++析构器
//对象是否引用计数是否存储在SideTable中
if (fastpath(isa.nonpointer &&
!isa.weakly_referenced &&
!isa.has_assoc &&
!isa.has_cxx_dtor &&
!isa.has_sidetable_rc))
{
//assert对象是否使用了SideTable
assert(!sidetable_present());
//C语言的直接释放
free(this);
}
else {
object_dispose((id)this);
}
}
object_dispose ---> objc_destructInstance
判断是否有c++析构函数
判断是否有关联对象
判断是否存在弱引用
判断SideTable是否记录了引用计数
id
object_dispose(id obj)
{
if (!obj) return nil;
objc_destructInstance(obj);
free(obj);
return nil;
}
void *objc_destructInstance(id obj)
{
if (obj) {
// Read all of the flags at once for performance.
// 是否有c++析构函数
bool cxx = obj->hasCxxDtor();
// 是否有关联对象
bool assoc = obj->hasAssociatedObjects();
// This order is important.
// 如果有c++析构函数,则注销c++的ivars
if (cxx) object_cxxDestruct(obj);
// 如果有关联对象,则移除关联对象。
if (assoc) _object_remove_assocations(obj);
// 移除SideTable中记录的数据
obj->clearDeallocating();
}
return obj;
}
void _object_remove_assocations(id object)
这个方法主要是移除正在注销的对象的已关联对象。
它相反的过程,添加associations,_object_set_associative_reference
void _object_remove_assocations(id object) {
vector< ObjcAssociation,ObjcAllocator<ObjcAssociation> > elements;
{
// 关联对象的管理者
AssociationsManager manager;
// 静态变量associations
AssociationsHashMap &associations(manager.associations());
if (associations.size() == 0) return;
disguised_ptr_t disguised_object = DISGUISE(object);
// 在AssociationsHashMap中,查找ObjectAssociationMap
// map.find(key),查找关键字key,返回一个迭代器。
// 返回迭代器的原因是 为了兼容非连续内存存储,非连续索引的数据。
// 如果map.find(key) == map.end(),表示没有找到该key对应的数据。
AssociationsHashMap::iterator i = associations.find(disguised_object);
if (i != associations.end()) {
// copy all of the associations that need to be removed.
// ObjectAssociationMap是某一个对象所有的关联的对象
ObjectAssociationMap *refs = i->second;
for (ObjectAssociationMap::iterator j = refs->begin(), end = refs->end(); j != end; ++j) {
// ObjectAssociationMap中的value,就是被关联的对象。
elements.push_back(j->second);
}
// remove the secondary table.
// 删除正在注销的对象的所有弱引用对象。删除ObjectAssociationMap
delete refs;
// 在全局的AssociationsHashMap里,删除 key--ObjectAssociationMap这组数据。
associations.erase(i);
}
}
// the calls to releaseValue() happen outside of the lock.
// 将数组elements中的所有ObjectAssociation清除。
for_each(elements.begin(), elements.end(), ReleaseValue());
}
struct ReleaseValue {
// 清除ObjcAssociation的value和policy
void operator() (ObjcAssociation &association) {
releaseValue(association.value(), association.policy());
}
};
static void releaseValue(id value, uintptr_t policy) {
if (policy & OBJC_ASSOCIATION_SETTER_RETAIN) {
return objc_release(value);
}
}
objc_object::clearDeallocating()
清除对象在SideTable中的数据,包括RefCountMap,weak_table_t
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());
}
//raw pointer使用
void
objc_object::sidetable_clearDeallocating()
{
SideTable& table = SideTables()[this];
// clear any weak table items
// clear extra retain count and deallocating bit
// (fixme warn or abort if extra retain count == 0 ?)
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();
}
//nonpointer使用
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();
}
总结
对象释放过程中,有几个关键:
1、引用计数
2、弱引用
3、关联对象
4、C++的析构函数