美文网首页
Dealloc 流程分析

Dealloc 流程分析

作者: KB_MORE | 来源:发表于2020-09-13 09:09 被阅读0次

//对象的内存销毁时间表

1.调用-release :引用计数变为零

  • 对象正在被销毁,生命周期即将结束.

  • 不能再有新的_ _weak 弱引用, 否则将指向nil.

  • 调用[self dealloc]

2.子类调用-dealloc

  • 继承关系中最底层的子类在调用-dealloc

  • 如果是MRC代码则会手动释放实例变量们(iVars)

  • 继承关系中每一层的父类都在调用-dealloc

3. NSObject 调用-dealloc

  • 只做- 件事:调用objective-C runtime中的object_ dispose() 方法

4.调用object_ dispose()

  • 为C++ 的实例变量们(iVars) 调用destructors

  • 为ARC状态下的实例变量们(iVars)调用-release

  • 解除所有使用runtime Associate方法关联的对象

  • 解除所有_ weak 引用

  • 调用free()

dealloc->_objc_rootDealloc->rootDealloc->object_dispose->objc_destructInstance

1. dealloc

- (void)dealloc {
    _objc_rootDealloc(self);
}

2._objc_rootDealloc

void
_objc_rootDealloc(id obj)
{
    ASSERT(obj);

    obj->rootDealloc();
}

3.rootDealloc

inline void
objc_object::rootDealloc()
{
    if (isTaggedPointer()) return;  // fixme necessary?

    if (fastpath(isa.nonpointer  &&  
                 !isa.weakly_referenced  &&  //弱引用
                 !isa.has_assoc  &&  //关联属性
                 !isa.has_cxx_dtor  &&  //析构函数
                 !isa.has_sidetable_rc))//引用计数
    {
        assert(!sidetable_present());
        free(this);
    } 
    else {
        object_dispose((id)this);//释放
    }
}

4.object_dispose

id 
object_dispose(id obj)
{
    if (!obj) return nil;

    objc_destructInstance(obj);    
    free(obj);

    return nil;
}

5.objc_destructInstance


void *objc_destructInstance(id obj) 
{
    if (obj) {
        // Read all of the flags at once for performance.
        bool cxx = obj->hasCxxDtor();
        bool assoc = obj->hasAssociatedObjects();

        // This order is important.
        if (cxx) object_cxxDestruct(obj);//调用析构函数
        if (assoc) _object_remove_assocations(obj);//移除关联对象
        obj->clearDeallocating();//清理
    }

    return obj;
}

5.1 object_cxxDestructFromClass

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);

    // Call cls's dtor first, then superclasses's dtors.

    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);
        }
    }
}

    inline void releaseHeldValue() {
        if (_value && (_policy & OBJC_ASSOCIATION_SETTER_RETAIN)) {
            objc_release(_value);
        }
    }

5.2 _object_remove_assocations

HashMap查找删除关联属性

void
_object_remove_assocations(id object)
{
    ObjectAssociationMap refs{};

    {
        AssociationsManager manager;
        AssociationsHashMap &associations(manager.get());
        AssociationsHashMap::iterator i = associations.find((objc_object *)object);
        if (i != associations.end()) {
            refs.swap(i->second);
            associations.erase(i);
        }
    }

    // release everything (outside of the lock).
    for (auto &i: refs) {
        i.second.releaseHeldValue();
    }
}

5.3 clearDeallocating


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());
}

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();
}


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;
    }
    
    for (size_t i = 0; i < count; ++i) {
        objc_object **referrer = referrers[i];
        if (referrer) {
            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_entry_remove(weak_table, entry);
}


相关文章

网友评论

      本文标题:Dealloc 流程分析

      本文链接:https://www.haomeiwen.com/subject/fyknektx.html