美文网首页
OC底层原理探索—类的加载(2)

OC底层原理探索—类的加载(2)

作者: 十年开发初学者 | 来源:发表于2021-07-20 10:52 被阅读0次

    上篇文章我们探索了read_images里面的几个比较重要的流程,这篇我们接着上篇文章剩下的realizeClassWithoutSwift方法来讲解

    realizeClassWithoutSwift

    static Class realizeClassWithoutSwift(Class cls, Class previously)
    {
        runtimeLock.assertLocked();
    
        class_rw_t *rw;
        Class supercls;
        Class metacls;
    
        if (!cls) return nil;
        if (cls->isRealized()) {
            validateAlreadyRealizedClass(cls);
            return cls;
        }
        ASSERT(cls == remapClass(cls));
    
        // fixme verify class is not in an un-dlopened part of the shared cache?
        //从mach-O中获取数据data,转换成class_ro_t
        auto ro = (const class_ro_t *)cls->data();
        auto isMeta = ro->flags & RO_META;
        
        const char *mangledName = cls->nonlazyMangledName();
        if (strcmp(mangledName, "LGPerson") == 0)
        {
            if (!isMeta) {
                printf("%s LGPerson....\n",__func__);
            }
        }
        //判断是否时元类
        if (ro->flags & RO_FUTURE) {
            // This was a future class. rw data is already allocated.
            rw = cls->data();
            ro = cls->data()->ro();
            ASSERT(!isMeta);
            cls->changeInfo(RW_REALIZED|RW_REALIZING, RW_FUTURE);
        } else {
            // Normal class. Allocate writeable class data.
            //开辟rw的空间
            rw = objc::zalloc<class_rw_t>();
            //将ro赋值给rw
            rw->set_ro(ro);
            // flags:1 为当前类   2:元类
            rw->flags = RW_REALIZED|RW_REALIZING|isMeta;
            //给cls设置rw
            cls->setData(rw);
        }
    
        cls->cache.initializeToEmptyOrPreoptimizedInDisguise();
    
    #if FAST_CACHE_META
        if (isMeta) cls->cache.setBit(FAST_CACHE_META);
    #endif
    
        // Choose an index for this class.
        // Sets cls->instancesRequireRawIsa if indexes no more indexes are available
        cls->chooseClassArrayIndex();
    
        if (PrintConnecting) {
            _objc_inform("CLASS: realizing class '%s'%s %p %p #%u %s%s",
                         cls->nameForLogging(), isMeta ? " (meta)" : "", 
                         (void*)cls, ro, cls->classArrayIndex(),
                         cls->isSwiftStable() ? "(swift)" : "",
                         cls->isSwiftLegacy() ? "(pre-stable swift)" : "");
        }
    
        // Realize superclass and metaclass, if they aren't already.
        // This needs to be done after RW_REALIZED is set above, for root classes.
        // This needs to be done after class index is chosen, for root metaclasses.
        // This assumes that none of those classes have Swift contents,
        //   or that Swift's initializers have already been called.
        //   fixme that assumption will be wrong if we add support
        //   for ObjC subclasses of Swift classes.
        // 递归,加载父类、元类的实现
        supercls = realizeClassWithoutSwift(remapClass(cls->getSuperclass()), nil);
        metacls = realizeClassWithoutSwift(remapClass(cls->ISA()), nil);
    
        if (strcmp(mangledName, "LGPerson") == 0)
        {
            if (!isMeta) {
                printf("%s LGPerson....\n",__func__);
            }
        }
        
    #if SUPPORT_NONPOINTER_ISA
        if (isMeta) {
            // Metaclasses do not need any features from non pointer ISA
            // This allows for a faspath for classes in objc_retain/objc_release.
            cls->setInstancesRequireRawIsa();
        } else {
            // Disable non-pointer isa for some classes and/or platforms.
            // Set instancesRequireRawIsa.
            bool instancesRequireRawIsa = cls->instancesRequireRawIsa();
            bool rawIsaIsInherited = false;
            static bool hackedDispatch = false;
    
            if (DisableNonpointerIsa) {
                // Non-pointer isa disabled by environment or app SDK version
                instancesRequireRawIsa = true;
            }
            else if (!hackedDispatch  &&  0 == strcmp(ro->getName(), "OS_object"))
            {
                // hack for libdispatch et al - isa also acts as vtable pointer
                hackedDispatch = true;
                instancesRequireRawIsa = true;
            }
            else if (supercls  &&  supercls->getSuperclass()  &&
                     supercls->instancesRequireRawIsa())
            {
                // This is also propagated by addSubclass()
                // but nonpointer isa setup needs it earlier.
                // Special case: instancesRequireRawIsa does not propagate
                // from root class to root metaclass
                instancesRequireRawIsa = true;
                rawIsaIsInherited = true;
            }
    
            if (instancesRequireRawIsa) {
                cls->setInstancesRequireRawIsaRecursively(rawIsaIsInherited);
            }
        }
    // SUPPORT_NONPOINTER_ISA
    #endif
        ////    建立链表关系
        // Update superclass and metaclass in case of remapping
        cls->setSuperclass(supercls);
        cls->initClassIsa(metacls);
    
        // Reconcile instance variable offsets / layout.
        // This may reallocate class_ro_t, updating our ro variable.
        if (supercls  &&  !isMeta) reconcileInstanceVariables(cls, supercls, ro);
    
        // Set fastInstanceSize if it wasn't set already.
        cls->setInstanceSize(ro->instanceSize);
    
        // Copy some flags from ro to rw
        if (ro->flags & RO_HAS_CXX_STRUCTORS) {
            cls->setHasCxxDtor();
            if (! (ro->flags & RO_HAS_CXX_DTOR_ONLY)) {
                cls->setHasCxxCtor();
            }
        }
        
        // Propagate the associated objects forbidden flag from ro or from
        // the superclass.
        if ((ro->flags & RO_FORBIDS_ASSOCIATED_OBJECTS) ||
            (supercls && supercls->forbidsAssociatedObjects()))
        {
            rw->flags |= RW_FORBIDS_ASSOCIATED_OBJECTS;
        }
    
        // Connect this class to its superclass's subclass lists
        if (supercls) {
            addSubclass(supercls, cls);
        } else {
            addRootClass(cls);
        }
    
        // Attach categories
        methodizeClass(cls, previously);
    
        return cls;
    }
    

    1.首先进行判断,判断类是否存在,如果不存在直接返回nil,然后在判断这个类是否已经验证实现,如果实现则返回当前类,只要时因为这个地方也存在递归实现元类与父类根类的父类为nil元类的isa指向自己,所以这样可以保证类只会被初始化一次

        if (!cls) return nil;
        if (cls->isRealized()) {
            validateAlreadyRealizedClass(cls);
            return cls;
        }
    

    2.rw的初始化

    • ro:clean memory,在编译期间确定的内存空间,只读不可改变,其存储着类名称、属性、协议、方法、实例变量
    • rw: dirty memory,在 运行时 生成,可读可写,由于其动态性,可以往类中添加属性、方法、协议
    • rwe :类的额外信息,只有不到10%的类真正的更改了他们的方法,并不是每一个类都需要插入数据,进行修改的类很少,避免资源的消耗,所以就有了rwe。rwe中存储的一般是分类的信息、动态添加的方法
        auto ro = (const class_ro_t *)cls->data();
        auto isMeta = ro->flags & RO_META;
        
     
        //判断是否时元类
        if (ro->flags & RO_FUTURE) {
            // This was a future class. rw data is already allocated.
            rw = cls->data();
            ro = cls->data()->ro();
            ASSERT(!isMeta);
            cls->changeInfo(RW_REALIZED|RW_REALIZING, RW_FUTURE);
        } else {
            // Normal class. Allocate writeable class data.
            //开辟rw的空间
            rw = objc::zalloc<class_rw_t>();
            //将ro赋值给rw
            rw->set_ro(ro);
            // flags:1 为当前类   2:元类
            rw->flags = RW_REALIZED|RW_REALIZING|isMeta;
            //给cls设置rw
            cls->setData(rw);
        }
    

    3.对类的父类和元类进行递归处理,是为了设置superClass的继承链和isa的走位图

    
        //递归调用realizeClassWithoutSwift完善继承链,并处理当前类的父类、元类
        //递归实现 设置当前类、父类、元类的 rw,主要目的是确定继承链 (类继承链、元类继承链)
        //实现元类、父类
        //当isa找到根元类之后,根元类的isa是指向自己的,不会返回nil从而导致死循环——remapClass中对类在表中进行查找的操作,如果表中已有该类,则返回一个空值;如果没有则返回当前类,这样保证了类只加载一次并结束递归
        supercls = realizeClassWithoutSwift(remapClass(cls->superclass), nil);
        metacls = realizeClassWithoutSwift(remapClass(cls->ISA()), nil);
        
    ...
    
    // Update superclass and metaclass in case of remapping -- class 是 双向链表结构 即父子关系都确认了
    // 将父类和元类给我们的类 分别是isa和父类的对应值
    cls->superclass = supercls;
    cls->initClassIsa(metacls);
    
    ...
    
    // Connect this class to its superclass's subclass lists
    //双向链表指向关系 父类中可以找到子类 子类中也可以找到父类
    //通过addSubclass把当前类放到父类的子类列表中去
    if (supercls) {
        addSubclass(supercls, cls);
    } else {
        addRootClass(cls);
    }
    
    

    methodizeClass分析

    static void methodizeClass(Class cls, Class previously)
    {
        runtimeLock.assertLocked();
        bool isMeta = cls->isMetaClass();
        const char *mangledName = cls->nonlazyMangledName();
        if (strcmp(mangledName, "LGPerson") == 0)
        {
            if (!isMeta) {
                printf("%s -LGPerson....\n",__func__);
            }
        }
        auto rw = cls->data();
        auto ro = rw->ro();
        auto rwe = rw->ext();
        
    
        // Methodizing for the first time
        if (PrintConnecting) {
            _objc_inform("CLASS: methodizing class '%s' %s", 
                         cls->nameForLogging(), isMeta ? "(meta)" : "");
        }
    
        // Install methods and properties that the class implements itself.
        //将属性列表、方法列表、协议列表等贴到rwe中
        // 将ro中的方法列表加入到rwe中
        method_list_t *list = ro->baseMethods();
        if (list) {
            prepareMethodLists(cls, &list, 1, YES, isBundleClass(cls), nullptr);
            if (rwe) rwe->methods.attachLists(&list, 1);
        }
        //将属性添加到rwe中
        property_list_t *proplist = ro->baseProperties;
        if (rwe && proplist) {
            rwe->properties.attachLists(&proplist, 1);
        }
        //将协议添加到rwe中
        protocol_list_t *protolist = ro->baseProtocols;
        if (rwe && protolist) {
            rwe->protocols.attachLists(&protolist, 1);
        }
    
        // Root classes get bonus method implementations if they don't have 
        // them already. These apply before category replacements.
        if (cls->isRootMetaclass()) {
            // root metaclass
            addMethod(cls, @selector(initialize), (IMP)&objc_noop_imp, "", NO);
        }
        //// 加入分类中的方法
        // Attach categories.
        if (previously) {
            if (isMeta) {
                objc::unattachedCategories.attachToClass(cls, previously,
                                                         ATTACH_METACLASS);
            } else {
                objc::unattachedCategories.attachToClass(cls, previously,
                                                         ATTACH_CLASS_AND_METACLASS);
            }
        }
        objc::unattachedCategories.attachToClass(cls, cls,
                                                 isMeta ? ATTACH_METACLASS : ATTACH_CLASS);
    
    #if DEBUG
        // Debug: sanity-check all SELs; log method list contents
        for (const auto& meth : rw->methods()) {
            if (PrintConnecting) {
                _objc_inform("METHOD %c[%s %s]", isMeta ? '+' : '-', 
                             cls->nameForLogging(), sel_getName(meth.name()));
            }
            ASSERT(sel_registerName(sel_getName(meth.name())) == meth.name());
        }
    #endif
    }
    
    
    rwe的逻辑

    方法列表添加至rwe逻辑

    • 获取ro的baseMethods
    • 通过prepareMethodLists方法排序
    • rwe进行处理即通过attachLists插入

    方法排序 -prepareMethodLists方法

    static void 
    prepareMethodLists(Class cls, method_list_t **addedLists, int addedCount,
                       bool baseMethods, bool methodsFromBundle, const char *why)
    {
    ...
    
        for (int i = 0; i < addedCount; i++) {
            method_list_t *mlist = addedLists[I];
            ASSERT(mlist);
    
            // Fixup selectors if necessary
            if (!mlist->isFixedUp()) {
                fixupMethodList(mlist, methodsFromBundle, true/*sort*/);
            }
        }
    ...
    }
    
    

    prepareMethodLists方法中 进行排序的主要方法fixupMethodList为这个方法

    static void 
    fixupMethodList(method_list_t *mlist, bool bundleCopy, bool sort)
    {
        runtimeLock.assertLocked();
        ASSERT(!mlist->isFixedUp());
    
        // fixme lock less in attachMethodLists ?
        // dyld3 may have already uniqued, but not sorted, the list
        if (!mlist->isUniqued()) {
            mutex_locker_t lock(selLock);
        
            // Unique selectors in list.
            for (auto& meth : *mlist) {
                const char *name = sel_cname(meth.name());
                meth.setName(sel_registerNameNoLock(name, bundleCopy));
            }
        }
    
    //排序
        if (sort && !mlist->isSmallList() && mlist->entsize() == method_t::bigSize) {
            method_t::SortBySELAddress sorter;
            std::stable_sort(&mlist->begin()->big(), &mlist->end()->big(), sorter);
        }
    
        // Mark method list as uniqued and sorted.
        // Can't mark small lists, since they're immutable.
        if (!mlist->isSmallList()) {
            mlist->setFixedUp();
        }
    }
    
    

    接下来我们来验证一下这里是否是在进行方法的排序

    image.png

    这里在排序之前实际上已经排好序了,主要是跟编译器有关,实在是整不出没有排好序的了。这里看下排序后的地址是由小到大进行排列的

    总结:关于这部分的流程

    _read_images->relizeClassWithoutSwift(对于ro、rw的操作)->methodizeClass->prepareMethodLists->fixupMethodList (主要是方法排序)

    懒加载类与非懒加载类

    非懒加载类

    回到_read_images方法,中的类的加载处理部分

    
        // Category discovery MUST BE Late to avoid potential races
        // when other threads call the new category code before
        // this thread finishes its fixups.
    
        // +load handled by prepare_load_methods()
    
        // Realize non-lazy classes (for +load methods and static instances)
        for (EACH_HEADER) {
            classref_t const *classlist = hi->nlclslist(&count);
            for (i = 0; i < count; i++) {
                Class cls = remapClass(classlist[i]);
                if (!cls) continue;
                const char *mangledName = cls->nonlazyMangledName();
                if (strcmp(mangledName, "LGPerson") == 0)
                {
                    printf("%s LGPerson....\n",__func__);
                }
                addClassTableEntry(cls);
    
                if (cls->isSwiftStable()) {
                    if (cls->swiftMetadataInitializer()) {
                        _objc_fatal("Swift class %s with a metadata initializer "
                                    "is not allowed to be non-lazy",
                                    cls->nameForLogging());
                    }
                    // fixme also disallow relocatable classes
                    // We can't disallow all Swift classes because of
                    // classes like Swift.__EmptyArrayStorage
                }
                realizeClassWithoutSwift(cls, nil);
            }
        }
    
    • 我们将LGPerson中的load方法去掉,再次运行程序,断点是不进入的
    • 这里涉及到懒加载类与非懒加载类,如果有load方法就会进行非懒加载,程序启动的时候就会进行以上ro,rw,排序等耗时操作
    懒加载类

    非懒加载类即程序启动时便会加载,效率很低,所以苹果采用了按需加载,也就是懒加载类,等需要时再加载。

    此时在main.m中初始化我们的类

    int main(int argc, const char * argv[]) {
        @autoreleasepool {
    
            // class_data_bits_t
            LGPerson * person = [LGPerson alloc];
    
        }
        return 0;
    }
    

    realizeClassWithoutSwift方法中添加该类的断点

    image.png

    image.png
    此时bt下查看函数调用栈,发现了lookUpImpOrForward函数,所以懒加载类的加载是在消息的慢速查找流程中调用

    相关文章

      网友评论

          本文标题:OC底层原理探索—类的加载(2)

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