#dealloc源码分析
- (void)dealloc {
_objc_rootDealloc(self);
}
void _objc_rootDealloc(id obj)
{
assert(obj);
obj->rootDealloc();
}
inline void objc_object::rootDealloc()
{
if (isTaggedPointer()) return;
if (fastpath(isa.nonpointer &&
!isa.weakly_referenced &&
!isa.has_assoc &&
!isa.has_cxx_dtor &&
!isa.has_sidetable_rc))
{
//如果该isa是一个nonpointer且没有弱引用计数、没有关联对象、没有c++析构器、没有用到sideTable来处理引用计数,直接free
assert(!sidetable_present());
free(this);
}
else {
object_dispose((id)this);
}
}
id object_dispose(id obj)
{
if (!obj) return nil;
objc_destructInstance(obj); //真正析构去处理的一些事情
free(obj);
return nil;
}
void *objc_destructInstance(id obj)
{
if (obj) {
//获取isa一些标志位
bool cxx = obj->hasCxxDtor(); //是否有c++的析构
bool assoc = obj->hasAssociatedObjects(); //是否有关联对象(什么是关联对象?比如给某个系统类添加的某个属性,就是关联对象,系统维护了一张全局的关联对象map)
// This order is important.
if (cxx) object_cxxDestruct(obj); //执行c++的析构
if (assoc) _object_remove_assocations(obj); //去除关联对象
obj->clearDeallocating(); //
}
return obj;
}
复制代码
下面分别来看这三步清除操作: #####object_cxxDestruct
void object_cxxDestruct(id obj)
{
if (!obj) return;
if (obj->isTaggedPointer()) return;
object_cxxDestructFromClass(obj, obj->ISA());
}
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);
}
}
}
复制代码
代码也不难理解,沿着继承链遍历搜寻SEL_cxx_destruct这个selector,找到函数实现(void (*)(id)(函数指针)并执行。 #####_object_remove_assocations
void _object_remove_assocations(id object) {
vector< ObjcAssociation,ObjcAllocator > elements;
{
AssociationsManager manager; //全局的管理对象manager
AssociationsHashMap &associations(manager.associations()); //获取到对应关联的所有对象
if (associations.size() == 0) return;
disguised_ptr_t disguised_object = DISGUISE(object);
AssociationsHashMap::iterator i = associations.find(disguised_object); 找到对应的map
if (i != associations.end()) { //遍历哈希map
// copy all of the associations that need to be removed.
//拷贝所有需要删除的关联对象
ObjectAssociationMap *refs = i->second;
for (ObjectAssociationMap::iterator j = refs->begin(), end = refs->end(); j != end; ++j) {
elements.push_back(j->second);
}
// remove the secondary table.
// 移除
delete refs;
associations.erase(i);
}
}
// 释放每一个value
for_each(elements.begin(), elements.end(), ReleaseValue());
}
复制代码
#####clearDeallocating
inline void objc_object::clearDeallocating()
{
if (slowpath(!isa.nonpointer)) {
// 不是nonpointer
sidetable_clearDeallocating();
}
else if (slowpath(isa.weakly_referenced || isa.has_sidetable_rc)) {
//isa有弱引用表 或者 isa有sideTable的引用计数
clearDeallocating_slow();
}
assert(!sidetable_present());
}
复制代码
#####先看if
void objc_object::sidetable_clearDeallocating()
{
SideTable& table = SideTables()[this]; //获取到sideTable
table.lock();
RefcountMap::iterator it = table.refcnts.find(this); //找到引用计数的refCountMap
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(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; //拿到entry里的referrers
count = TABLE_SIZE(entry);
}
else {
referrers = entry->inline_referrers; //拿到weak_entry里的referrers
count = WEAK_INLINE_COUNT;
}
for (size_t i = 0; i < count; ++i) { //遍历referrers
objc_object **referrer = referrers[i];
if (referrer) {
if (*referrer == referent) { //将每个元素置为nil,所以weak修饰的变量释放是安全的
*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_entry_remove(weak_table, entry); //最后从sideTable中移除该weak_entry
}
static void weak_entry_remove(weak_table_t *weak_table, weak_entry_t *entry)
{
// remove entry
if (entry->out_of_line()) free(entry->referrers); //直接free
bzero(entry, sizeof(*entry)); //回收内存
weak_table->num_entries--; //设置weak_table的num_entries--
weak_compact_maybe(weak_table);
}
复制代码
再看else
clearDeallocating_slow,其实跟上面类似,也是走到了weak_clear_no_lock->weak_entry_remove
NEVER_INLINE void
objc_object::clearDeallocating_slow()
{
assert(isa.nonpointer && (isa.weakly_referenced || isa.has_sidetable_rc));
SideTable& table = SideTables()[this]; //获取到sideTable
table.lock();
if (isa.weakly_referenced) {
weak_clear_no_lock(&table.weak_table, (id)this);
}
if (isa.has_sidetable_rc) { //这边处理完之后,需要判断是否用了sideTable的引用计数 有的话去移除
table.refcnts.erase(this);
}
table.unlock();
}
复制代码
#####总结一下 dealloc流程:
- objc_release
- 因为引用计数为0所以开始执行dealloc
- 判断一些标志位((isa.nonpointer &&
!isa.weakly_referenced &&
!isa.has_assoc &&
!isa.has_cxx_dtor &&
!isa.has_sidetable_rc))),没有就直接free - 执行objc_destructInstance,这里分两步(3和4)
- 判断 obj->hasCxxDtor(); obj->hasAssociatedObjects(); 分别执行object_cxxDestruct和_object_remove_assocations
- 执行clearDeallocating,分两种情况:sidetable_clearDeallocating和clearDeallocating_slow,并最终都走向了:weak_clear_no_lock
- 遍历weak_entry里的referrers,并置为nil,如果判断isa.has_sidetable_rc去执行 table.refcnts.erase(this)清理引用计数map;
#weak 先来写一段代码,查看一下调用堆栈:
NSObject * obj = [NSObject alloc]; __weak typeof(NSObject *) weakObj = obj;
可以看到,weak的创建是通过objc_initWeak函数,销毁是通过objc_destroyWeak。 // 上述代码会被编译器处理: id __weak weakObj; objc_initWeak(&weakObj, obj); objc_destroyWeak(&weakObj); // 离开变量的范围,进行销毁 #####下面我们进入源码解析: #weak的创建流程 #####weak存放的位置 在[NONPOINTER_ISA和散列表]( www.jianshu.com/p/f5305144c…里介绍了弱引用表weak_table_t是存放在sideTable中,weak_table_t含有一个属性weak_entry_t *weak_entries,它是负责维护和存储指向一个对象的所有弱引用hash表,weak_entry_t本身也是一个结构体,其定义如下:
struct weak_entry_t {
DisguisedPtr referent; /被引用的对象
union {
struct {
weak_referrer_t *referrers; //weak_referrer_t 类型的数组,用来存放弱引用变量的地址
uintptr_t out_of_line_ness : 2;
uintptr_t num_refs : PTR_MINUS_2;
uintptr_t mask;
uintptr_t max_hash_displacement;
};
};
};
复制代码
weak_entry_t里有一个对象,还有一个要存放弱引用变量地址的数组。
#####源码解析
id
objc_initWeak(id *location, id newObj)
{
if (!newObj) {
*location = nil;
return nil;
}
return storeWeak
(location, (objc_object*)newObj);
}
复制代码
static id
storeWeak(id *location, objc_object *newObj)
{
//异常判断
assert(haveOld || haveNew);
if (!haveNew) assert(newObj == nil);
Class previouslyInitializedClass = nil;
id oldObj;
SideTable *oldTable;
SideTable *newTable;
retry:
if (haveOld) {
oldObj = *location;
oldTable = &SideTables()[oldObj]; //有旧的table的话获取到oldTable
} else {
oldTable = nil;
}
if (haveNew) {
newTable = &SideTables()[newObj]; //获取到新的table
} else {
newTable = nil;
}
//加锁
SideTable::lockTwo(oldTable, newTable);
if (haveOld && *location != oldObj) { // location 应该与 oldObj 保持一致,如果不同,说明当前的 location 已经处理过 oldObj 可是又被其他线程所修改,进行重试
//解锁
SideTable::unlockTwo(oldTable, newTable);
goto retry;
}
if (haveNew && newObj) {
Class cls = newObj->getIsa(); // 获得新对象的 isa 指针
if (cls != previouslyInitializedClass &&
!((objc_class *)cls)->isInitialized())
{
SideTable::unlockTwo(oldTable, newTable); //解锁
_class_initialize(_class_getNonMetaClass(cls, (id)newObj)); //进行初始
previouslyInitializedClass = cls;
goto retry;
}
}
if (haveOld) { //如果有旧值,那么就清除
weak_unregister_no_lock(&oldTable->weak_table, oldObj, location);
}
if (haveNew) {
newObj = (objc_object *)
weak_register_no_lock(&newTable->weak_table, (id)newObj, location,
crashIfDeallocating); //注册新值
// 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(oldTable, newTable);
return (id)newObj;
}
复制代码
接下来,分别查看weak_register_no_lock和weak_unregister_no_lock,为了方便理解,只保留了部分关键代码: ####weak_register_no_lock
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;
// 创建一个entry
weak_entry_t *entry;
if ((entry = weak_entry_for_referent(weak_table, referent))) {
//如果在 weaktable中找到了referent,直接加进去
append_referrer(entry, referrer);
}
else {
//没找到
weak_entry_t new_entry(referent, referrer); 新建一个
weak_grow_maybe(weak_table); //判断是否需要扩容
weak_entry_insert(weak_table, &new_entry); //插入
}
return referent_id;
}
static weak_entry_t *
weak_entry_for_referent(weak_table_t *weak_table, objc_object *referent)
{
assert(referent);
//取到weaktable里的weak_entries那个数组
weak_entry_t *weak_entries = weak_table->weak_entries;
if (!weak_entries) return nil;
size_t begin = hash_pointer(referent) & weak_table->mask;
size_t index = begin;
size_t hash_displacement = 0;
//这个循环就是遍历weak_entries去寻找一个适合的下标来进行插入,如果找到了就返回
while (weak_table->weak_entries[index].referent != referent) {
index = (index+1) & weak_table->mask;
if (index == begin) bad_weak_table(weak_table->weak_entries);
hash_displacement++;
if (hash_displacement > weak_table->max_hash_displacement) {
return nil;
}
}
return &weak_table->weak_entries[index];
}
//找到的话,开始append
static void append_referrer(weak_entry_t *entry, objc_object **new_referrer)
{
//new_referrer是需要插入的地址
if (! entry->out_of_line()) {
// 处理weak_entry_t还在使用inline数组的情况。首先尝试像inline数组中插入一个新的弱引用
for (size_t i = 0; i < WEAK_INLINE_COUNT; i++) {
if (entry->inline_referrers[i] == nil) {
entry->inline_referrers[i] = new_referrer;
return;
}
}
// 如果inline数组已满,那就创建一个WEAK_INLINE_COUNT大小的新数组,改用outline的方式,将inline数组中的元素依次拷贝过来。
weak_referrer_t *new_referrers = (weak_referrer_t *)
calloc(WEAK_INLINE_COUNT, sizeof(weak_referrer_t));
for (size_t i = 0; i < WEAK_INLINE_COUNT; i++) {
new_referrers[i] = entry->inline_referrers[i];
}
entry->referrers = new_referrers;
entry->num_refs = WEAK_INLINE_COUNT;
entry->out_of_line_ness = REFERRERS_OUT_OF_LINE;
entry->mask = WEAK_INLINE_COUNT-1;
entry->max_hash_displacement = 0;
}
assert(entry->out_of_line());
if (entry->num_refs >= TABLE_SIZE(entry) * 3/4) {
//如果当前容量占了总容量的%75 那么就要进行扩容,再添加
return grow_refs_and_insert(entry, new_referrer);
}
size_t begin = w_hash_pointer(new_referrer) & (entry->mask);
size_t index = begin;
size_t hash_displacement = 0;
while (entry->referrers[index] != nil) { //
hash_displacement++;
index = (index+1) & entry->mask;
if (index == begin) bad_weak_table(entry);
}
if (hash_displacement > entry->max_hash_displacement) {
entry->max_hash_displacement = hash_displacement;
}
weak_referrer_t &ref = entry->referrers[index];
ref = new_referrer;
entry->num_refs++;
}
//没找到的话,创建一个
struct weak_entry_t {
weak_entry_t(objc_object *newReferent, objc_object **newReferrer)
: referent(newReferent)
{
//初始化时直接在第0个下标赋上newReferrer
inline_referrers[0] = newReferrer;
//别的都是nil
for (int i = 1; i < WEAK_INLINE_COUNT; i++) {
inline_referrers[i] = nil;
}
}
};
static void weak_entry_insert(weak_table_t *weak_table, weak_entry_t *new_entry)
{
//此时的entry还不在weaktable中
weak_entry_t *weak_entries = weak_table->weak_entries;
assert(weak_entries != nil);
size_t begin = hash_pointer(new_entry->referent) & (weak_table->mask);
size_t index = begin;
size_t hash_displacement = 0;
//哈希运算获取合适的下标位置
while (weak_entries[index].referent != nil) {
index = (index+1) & weak_table->mask;
if (index == begin) bad_weak_table(weak_entries);
hash_displacement++;
}
weak_entries[index] = *new_entry; //给该下标赋值
weak_table->num_entries++; //同时更新num_entries
if (hash_displacement > weak_table->max_hash_displacement) {
weak_table->max_hash_displacement = hash_displacement;
}
}
复制代码
####weak_unregister_no_lock
void
weak_unregister_no_lock(weak_table_t *weak_table, id referent_id,
id *referrer_id)
{
objc_object *referent = (objc_object *)referent_id;
objc_object **referrer = (objc_object **)referrer_id;
weak_entry_t *entry;
if (!referent) return;
if ((entry = weak_entry_for_referent(weak_table, referent))) { //找到对应的弱引用项
remove_referrer(entry, referrer); //将对应的弱引用变量位置移除
bool empty = true;
if (entry->out_of_line() && entry->num_refs != 0) {
empty = false;
}
else {
for (size_t i = 0; i < WEAK_INLINE_COUNT; i++) {
if (entry->inline_referrers[i]) {
empty = false;
break;
}
}
}
if (empty) { //判断weaktable中的weak_entry_t是否为空,为空则使用 weak_entry_remove 将其从弱引用表中整个移除。
weak_entry_remove(weak_table, entry);
}
}
}
复制代码
在变量作用域结束时通过objc_destroyWeak 函数释放该变量。
void
objc_destroyWeak(id *location)
{
/**这里跟objc_initWeak 都调用了storeWeak,不同的是传参不一样
objc_initWeak: DontHaveOld DoHaveNew
objc_destroyWeak : DoHaveOld DontHaveNew
*/
(void)storeWeak
(location, nil);
在storeWeak中就直接走到了weak_unregister_no_lock
}
复制代码
总结一下基本步骤如下:
- 找到对应的sideTable
- 从sideTable中拿到弱引用表weaktable,并获得其weak_entry_t
- 如果有旧值,则先从oldTable中清除旧值:weak_unregister_no_lock
- 把新值注册进newTable:weak_register_no_lock
- 如果newTable中,去referent对应的referrers中寻找合适的下标进行插入:weak_entry_for_referent ——> append_referrer,over。否则进入第6步
- 没有找到合适的下标的话,就新建一个weak_entry_t,并在初始化时添加newReferrer到第0个下标
- 新建完后去判断是否需要扩容:weak_grow_maybe
- 把新建的weak_entry_t插入weaktable,并设置weaktable的num_entries +1