Runtime源碼閱讀分享之對象的生命週期

簡介

  • 這篇文章主要介紹的內容包括根據源碼來理解對象從「出生」到「消亡」的整個生命週期。

對象的出生

  • alloc 方法作了什麼?html

    // 由源碼可知
    + (id)alloc {
        return _objc_rootAlloc(self);
    }
    
    // 接着👇
    id _objc_rootAlloc(Class cls)  
    {
        return callAlloc(cls, false/*checkNil*/, true/*allocWithZone*/);
    }
    
    // 接着👇
    static ALWAYS_INLINE id callAlloc(Class cls, bool checkNil, bool allocWithZone=false) {
        if (checkNil && !cls) return nil;
    
    #if __OBJC2__
      // 首先判斷當前類是否 hasCustomAWZ ,該方法定義以下
      /** bool hasCustomAWZ() { return ! bits.hasDefaultAWZ(); } bool hasDefaultAWZ() { return data()->flags & RW_HAS_DEFAULT_AWZ; } 而 RW_HAS_DEFAULT_AWZ 的定義以下:表示是否擁有默認建立方法 // class or superclass has default alloc/allocWithZone: implementation // Note this is is stored in the metaclass. #define RW_HAS_DEFAULT_AWZ (1<<16) */
    
      // 無默認建立方法
        if (! cls->ISA()->hasCustomAWZ()) {
            // No alloc/allocWithZone implementation. Go straight to the allocator.
            // fixme store hasCustomAWZ in the non-meta class and 
            // add it to canAllocFast's summary
            if (cls->canAllocFast()) {
                // No ctors, raw isa, etc. Go straight to the metal.
              // 判斷是否有析構函數
                bool dtor = cls->hasCxxDtor();
              // 直接初始化,而且置爲 0 
                id obj = (id)calloc(1, cls->bits.fastInstanceSize());
              // 建立失敗,則被 badHandler 捕獲
                if (!obj) return callBadAllocHandler(cls);
              // 而後初始化
                obj->initInstanceIsa(cls, dtor);
         
                return obj;
            } else {
                // Has ctor or raw isa or something. Use the slower path.
              
             /** // 若是沒法進行快速建立,則直接在 zone 中分配一塊空間來建立 id class_createInstance(Class cls, size_t extraBytes) { return _class_createInstanceFromZone(cls, extraBytes, nil); } */
                id obj = class_createInstance(cls, 0);
                if (!obj) return callBadAllocHandler(cls);
                return obj;
            }
        }
    #endif
    
        // No shortcuts available.
        if (allocWithZone) return [cls allocWithZone:nil];
        return [cls alloc];
    }
    複製代碼

  • 最終都調用了 _class_createInstanceFromZone 方法objective-c

    // 如今咱們來看一下這個方法
    static __attribute__((always_inline)) 
    id
    _class_createInstanceFromZone(Class cls, size_t extraBytes, void *zone, 
                                  bool cxxConstruct = true, 
                                  size_t *outAllocatedSize = nil)
    {
        if (!cls) return nil;
    
        assert(cls->isRealized());
    
        // Read class's info bits all at once for performance
      // 判斷是否有析構函數
        bool hasCxxCtor = cls->hasCxxCtor();
        bool hasCxxDtor = cls->hasCxxDtor();
      // 判斷是否可以快速初始化
        bool fast = cls->canAllocNonpointer();
    
      // 計算當前實例的大小
        size_t size = cls->instanceSize(extraBytes);
      
        if (outAllocatedSize) *outAllocatedSize = size;
    
        id obj;
        if (!zone  &&  fast) {
          // 若是 zone 爲空 而且能夠快速構造,則直接使用 calloc 函數快速構造一個 size 大小的位置
            obj = (id)calloc(1, size);
            if (!obj) return nil;
          // 初始化數據
            obj->initInstanceIsa(cls, hasCxxDtor);
        } 
        else {
          // 若是不支持快速構造而且有 zone,則直接在 zone 上分配一個 size 大小的存儲空間
            if (zone) {
                obj = (id)malloc_zone_calloc ((malloc_zone_t *)zone, 1, size);
          // 若是不支持快速構造而且無 zone,則直接使用 calloc 分配一個 size 大小的存儲空間
            } else {
                obj = (id)calloc(1, size);
            }
            if (!obj) return nil;
    
            // Use raw pointer isa on the assumption that they might be 
            // doing something weird with the zone or RR.
            obj->initIsa(cls);
        }
    
        if (cxxConstruct && hasCxxCtor) {
            obj = _objc_constructOrFree(obj, cls);
        }
    
        return obj;
    }
    複製代碼
  • 而咱們以後,須要調用 init 方法,來實現對象真正的完成出生過程swift

    - (id)init {
        return _objc_rootInit(self);
    }
    
    _objc_rootInit(id obj)
    {
        // In practice, it will be hard to rely on this function.
        // Many classes do not properly chain -init calls.
        return obj;
    }
    複製代碼

    至此,對象的出生真正完成併發

對象的生長

  • 首先定義以下類app

    #import <Foundation/Foundation.h>
    
    @interface LYObject : NSObject
    
    @property (nonatomic, strong) NSString *name;
    
    - (void)study;
    + (void)sleep;
    
    @end
      
    @implementation LYObject
    
    - (void)study {
        NSLog(@"studying");
    }
    
    + (void)sleep {
        NSLog(@"sleeping");
    }
    
    @end
    複製代碼
  • 而後在 viewController 中調用它ide

    - (void)testSuperClass {
        LYObject *obj = [[LYObject alloc] init];
        
        NSLog(@"class - %@", [obj class]);
        NSLog(@"superClass - %@", [obj superclass]);
        NSLog(@"metaClass -- %@", object_getClass([obj class]));
        NSLog(@"metaClass's metaClass -- %@", object_getClass(object_getClass([obj class])));
        NSLog(@"metaClass's superClass -- %@", [object_getClass([obj class]) superclass]);
        
        // 打印結果
        /**
         2017-12-28 21:16:43.972104+0800 RuntimeTest[60981:11200702] class - LYObject
         2017-12-28 21:16:43.972300+0800 RuntimeTest[60981:11200702] superClass - NSObject
         2017-12-28 21:16:43.972417+0800 RuntimeTest[60981:11200702] metaClass -- LYObject
         2017-12-28 21:16:43.972530+0800 RuntimeTest[60981:11200702] metaClass's metaClass -- NSObject
         2017-12-28 21:16:43.972626+0800 RuntimeTest[60981:11200702] metaClass's superClass -- NSObject
         */
    }
    
    - (void)testPoiter {
        Class currentClass = [LYObject class];
        for (int i = 1; i < 5; i++)
        {
            NSLog(@"Following the isa pointer %d times gives %p %@", i, currentClass,currentClass);
            currentClass = object_getClass(currentClass);
        }
        
        NSLog(@"NSObject's class is %p", [NSObject class]);
        NSLog(@"NSObject's meta class is %p", object_getClass([NSObject class]));
        NSLog(@"NSObject's meta class's meta class is %p", object_getClass(object_getClass([NSObject class])));
        
        /**
         2017-12-28 21:18:58.430792+0800 RuntimeTest[61004:11204340] Following the isa pointer 1 times gives 0x1036f3060 LYObject
         // 代表此時指向 LYObject 的類
         
         2017-12-28 21:18:58.430971+0800 RuntimeTest[61004:11204340] Following the isa pointer 2 times gives 0x1036f3038 LYObject
         // 此時指向 LYObject 的 meta class
         
         2017-12-28 21:18:58.431090+0800 RuntimeTest[61004:11204340] Following the isa pointer 3 times gives 0x1046aae58 NSObject
         // 此時指向 LYObject 的 meta class 的 superClass
         
         2017-12-28 21:18:58.431185+0800 RuntimeTest[61004:11204340] Following the isa pointer 4 times gives 0x1046aae58 NSObject
         // 表面實際上 NSObject 類的 meta class 指針指向本身
         
         2017-12-28 21:18:58.431277+0800 RuntimeTest[61004:11204340] NSObject's class is 0x1046aaea8
         2017-12-28 21:18:58.431501+0800 RuntimeTest[61004:11204340] NSObject's meta class is 0x1046aae58
         2017-12-28 21:18:58.431793+0800 RuntimeTest[61004:11204340] NSObject's meta class's meta class is 0x1046aae58
         */
    }
    複製代碼
  • 由這兩個方法能夠看出,實際上 LYObject 對象的 class 爲 LYObject, LYObject 類的 class(即metaClass)爲 LYObject, 可是 LYObject 的 metaClass 的 superClass 爲 NSObject,如圖函數

  • 咱們進一步能夠看到,在黑框中的兩個 class 其實是一對 classPair,在 Runtime 的代碼定義中以下:源碼分析

    /** @param superclass 表示這個方法首先指明新建 class 的 superclass,若是新建的 class 是一個 rootclass,則直接傳遞 nil @param name 表示新建立的 class 的 name, 這個 name 的修飾符爲 copy @param extraBytes 表示 The number of bytes to allocate for indexed ivars at the end of the class and metaclass objects. This should usually be \c 0. 一般爲 0 建立一對新的 class pair 的步驟, 首先,調用 objc_allocateClassPair 方法 而後,調用 class_addMethod or class_addIvars 來給當前的類添加編譯時的屬性 而後,調用 objc_registerClassPair 來註冊這個 class ,此時這個新的 class 就準備好了! 最後,在 Runtime 時期,動態的爲類添加 實例變量和 實例方法,而類方法應該被添加到 metaclass 中 */
    
    Class objc_allocateClassPair(Class superclass, const char *name, size_t extraBytes) {
        Class cls, meta;
        
        rwlock_writer_t lock(runtimeLock);
        
        // Fail if the class name is in use.
        // Fail if the superclass isn't kosher.
        if (getClass(name)  ||  !verifySuperclass(superclass, true/*rootOK*/)) {
            return nil;
        }
        
        // Allocate new classes.
        cls  = alloc_class_for_subclass(superclass, extraBytes);
        meta = alloc_class_for_subclass(superclass, extraBytes);
    
        // fixme mangle the name if it looks swift-y?
        objc_initializeClassPair_internal(superclass, name, cls, meta);
    
        return cls;
    }
    
    // 在上述方法中給 cls 和 meta 指針賦值時, 調用了 alloc_class_for_subclass 方法,這個方法實際上就是建立了一個類的地址空間給它使用。
    static Class alloc_class_for_subclass(Class supercls, size_t extraBytes) {
        if (!supercls  ||  !supercls->isSwift()) {
            return _calloc_class(sizeof(objc_class) + extraBytes);
        }
    }
    
    // 也調用了另外一個方法 objc_initializeClassPair_internal, 在這個方法中👇
    
    // &UnsetLayout is the default ivar layout during class construction
    static const uint8_t UnsetLayout = 0;
    
    static void objc_initializeClassPair_internal(Class superclass, const char *name, Class cls, Class meta) {
        runtimeLock.assertWriting();
    
      // 首先聲明兩個儲存類信息的指針
        class_ro_t *cls_ro_w, *meta_ro_w;
        
      // 爲 class_rw_t 結構體建立控件,而後初始化爲 0
        cls->setData((class_rw_t *)calloc(sizeof(class_rw_t), 1));
        meta->setData((class_rw_t *)calloc(sizeof(class_rw_t), 1));
        cls_ro_w   = (class_ro_t *)calloc(sizeof(class_ro_t), 1);
        meta_ro_w  = (class_ro_t *)calloc(sizeof(class_ro_t), 1);
      // 而後使 data() 返回的 class_rw_t 指針的 ro 變量指向剛剛聲明的兩個指針 cls_ro_w 和 meta_ro_w
        cls->data()->ro = cls_ro_w;
        meta->data()->ro = meta_ro_w;
    
    // 接着設置初始化信息
      /** // class allocated but not yet registered #define RW_CONSTRUCTING (1<<26) // class_rw_t->ro is heap copy of class_ro_t #define RW_COPIED_RO (1<<27) // Values for class_rw_t->flags // These are not emitted by the compiler and are never used in class_ro_t. // Their presence should be considered in future ABI versions. // class_t->data is class_rw_t, not class_ro_t #define RW_REALIZED (1<<31) // available for use // #define RW_20 (1<<20) // class has started realizing but not yet completed it #define RW_REALIZING (1<<19) */
        cls->data()->flags = RW_CONSTRUCTING | RW_COPIED_RO | RW_REALIZED | RW_REALIZING;
        meta->data()->flags = RW_CONSTRUCTING | RW_COPIED_RO | RW_REALIZED | RW_REALIZING;
      
      // 設置 version, 7 表示 meta class
        cls->data()->version = 0;
        meta->data()->version = 7;
      
      // 設置 flag RO_META 表示 meta class
        cls_ro_w->flags = 0;
        meta_ro_w->flags = RO_META;
      
      // 若是都沒有 superclass, 則爲 rootclass
        if (!superclass) {
            cls_ro_w->flags |= RO_ROOT;
            meta_ro_w->flags |= RO_ROOT;
        }
      
        if (superclass) {
            cls_ro_w->instanceStart = superclass->unalignedInstanceSize();
            meta_ro_w->instanceStart = superclass->ISA()->unalignedInstanceSize();
            cls->setInstanceSize(cls_ro_w->instanceStart);
            meta->setInstanceSize(meta_ro_w->instanceStart);
        } else {
            cls_ro_w->instanceStart = 0;
            meta_ro_w->instanceStart = (uint32_t)sizeof(objc_class);
            cls->setInstanceSize((uint32_t)sizeof(id));  // just an isa
            meta->setInstanceSize(meta_ro_w->instanceStart);
        }
      
        cls_ro_w->name = strdupIfMutable(name);
        meta_ro_w->name = strdupIfMutable(name);
      
        cls_ro_w->ivarLayout = &UnsetLayout;
        cls_ro_w->weakIvarLayout = &UnsetLayout;
      
        meta->chooseClassArrayIndex();
        cls->chooseClassArrayIndex();
      
        // Connect to superclasses and metaclasses
        cls->initClassIsa(meta);
        if (superclass) {
            meta->initClassIsa(superclass->ISA()->ISA());
            cls->superclass = superclass;
            meta->superclass = superclass->ISA();
            addSubclass(superclass, cls);
            addSubclass(superclass->ISA(), meta);
        } else {
    複製代碼

對象的銷燬

  • 當咱們對一個對象發送 dealloc 消息時優化

    // 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表明是否開啓isa指針優化。 weakly_referenced表明對象被指向或者曾經指向一個 ARC 的弱變量。 has_assoc表明對象含有或者曾經含有關聯引用。 has_cxx_dtor以前提到過了,是析構器。 has_sidetable_rc判斷該對象的引用計數是否過大。 */ 
        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);
        }
    }
    
    // 又調用
    id object_dispose(id obj) {
        if (!obj) return nil;
    
        objc_destructInstance(obj);    
        free(obj);
    
        return nil;
    }
    
    /*********************************************************************** * objc_destructInstance * Destroys an instance without freeing memory. * Calls C++ destructors. * Calls ARC ivar cleanup. * Removes associative references. * Returns `obj`. Does nothing if `obj` is nil. **********************************************************************/
    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;
    }
    複製代碼
  • 當調用 object_cxxDestruct 方法時,後續調用以下:ui

    /*********************************************************************** * 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);
            }
        }
          }
    
    /*********************************************************************** * 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))
              // 從子類開始沿着繼承鏈一直找到父類,向上搜尋 SEL_cxx_destruct 這個selector,找到函數實現(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);
            }
        }
          }
    複製代碼
  • 當調用 _object_remove_assocations 方法時,後續調用以下:

    void _object_remove_assocations(id object) {
        vector< ObjcAssociation,ObjcAllocator<ObjcAssociation> > elements;
        {
            AssociationsManager manager;
            AssociationsHashMap &associations(manager.associations());
            if (associations.size() == 0) return;
            disguised_ptr_t disguised_object = DISGUISE(object);
            AssociationsHashMap::iterator i = associations.find(disguised_object);
            if (i != associations.end()) {
                // 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);
            }
        }
        // the calls to releaseValue() happen outside of the lock.
        for_each(elements.begin(), elements.end(), ReleaseValue());
    }
    複製代碼
  • 至此,對象被銷燬

總結

  • 這次關於對象生命週期的源碼分析到這裏就結束了,因爲時間和精力有限,這裏只作了一個大概的瞭解,並無特別深刻的研究,但願有不一樣意見和建議的大佬們可以不吝賜教,謝謝!

參考資料

相關文章
相關標籤/搜索