ARC中dealloc进程以及.cxx_destruct的探究

ARC文档中对dealloc进程的解释

A class may provide a method definition for an instance method named dealloc. This method will be called after the final release of the object but before it is deallocated or any of its instance variables are destroyed. The superclass’s implementation of dealloc will be called automatically when the method returns.

大约意思是,dealloc办法在最终一次release后,在实例变量被毁掉之前,调用;父类的dealloc办法将在子类dealloc回来后主动调用;

The instance variables for an ARC-compiled class will be destroyed at some point after control enters the dealloc method for the root class of the class. The ordering of the destruction of instance variables is unspecified, both within a single class and between subclasses and superclasses.

大约意思是,ARC下的实例变量在调用根类的dealloc办法后被毁掉,实例变量毁掉的次序是不固定的,无论在子类还是父类;

所以,ARC下不主动调[super dealloc]是因为编译器主动调用了;

1.NSObject的析构进程

经过检查apple源码,能够看出NSObject调用dealloc实际上是调用了_objc_rootDealloc(源码在NSObject.mm中)

- (void)dealloc {
    _objc_rootDealloc(self);
}
_objc_rootDealloc(id obj)
{
    ASSERT(obj);
    obj->rootDealloc();
}

_objc_rootDealloc接着调用object_dispose(源码在objc-object.h)

objc_object::rootDealloc()
{
    if (isTaggedPointer()) return;
    object_dispose((id)this);
}

object_dispose最终调用objc_destructInstance(源码在objc-runtime-new.mm)

object_dispose(id obj)
{
    if (!obj) return nil;
    objc_destructInstance(obj);    
    free(obj);
    return nil;
}

能够看出objc_destructInstance详细做了三件事:

ARC中dealloc过程以及.cxx_destruct的探究

(1)履行object_cxxDestruct(详细做什么下面解释)

(2)履行_object_remove_assocations,删去相关目标的引证

(3)履行clearDeallocating,清空引证计数表并铲除弱引证表,将所有的weak引证指为nil。

2.object_cxxDestruct

持续查找object_cxxDestruct,能够看到最终调用了object_cxxDestructFromClass(源码objc-class.mm中)

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

代码不难理解,沿着继承链逐层向上查找SEL_cxx_destruct这个函数,找到函数完成并履行,现在就找到我们之前的.cxx_destruct办法。

初始化Test类,在如图断点处,输入lldb指令:

watchpoint set variable test->_address

将address的变量加入watchpoint

ARC中dealloc过程以及.cxx_destruct的探究

(lldb) watchpoint set variable test->_address
Watchpoint created: Watchpoint 1: addr = 0x10054b038 size = 8 state = enabled type = w
    watchpoint spec = 'test->_address'
    new value: 0x00000001000040a8
Watchpoint 1 hit:
old value: 0x00000001000040a8
new value: 0x0000000000000000

能够看出_address从 0x00000001000040a8 变成了 0x0000000000000000,也就是nil,看下调用栈,果然跟到了.cxx_destruct办法,并且是在objc_storeStrong的进程中开释。

ARC中dealloc过程以及.cxx_destruct的探究

总结: ARC下目标的成员变量于编译器刺进的.cxx_desctruct办法中开释; ARC下[super dealloc]办法由编译器主动刺进; cxx_destruct内部完成需进一步探索;