美文网首页
12、类的加载分析

12、类的加载分析

作者: ChenL | 来源:发表于2020-10-16 16:35 被阅读0次

    上篇已经说明了 map_images,但没有详细说明,下面我们来继续..

    1、_read_images分析

    1、条件控制进行一次的加载
    2、修复预编译阶段的 @selector的混乱问题
    3、错误混乱的类处理
    4、修复重映射一些没有被镜像文件加载进来的类
    5、修复一些消息
    6、当我们类里面有协议的时候:readProtocol
    7、修复没有被加载的协议
    8、分类处理
    9、类的加载处理
    10、没有被处理的类 优化那些侵犯的类

    void _read_images(header_info **hList, uint32_t hCount, int totalClasses, int unoptimizedTotalClasses)
    {
          里面的代码太多,就不一一说明了
    }
    
    // Discover classes. Fix up unresolved future classes. Mark bundle classes.
        bool hasDyldRoots = dyld_shared_cache_some_image_overridden();
    
        for (EACH_HEADER) {
            if (! mustReadClasses(hi, hasDyldRoots)) {
                // Image is sufficiently optimized that we need not call readClass()
                continue;
            }
    
            classref_t const *classlist = _getObjc2ClassList(hi, &count);
    
            bool headerIsBundle = hi->isBundle();
            bool headerIsPreoptimized = hi->hasPreoptimizedClasses();
    
           //确定类的继承关系
            for (i = 0; i < count; i++) {
                Class cls = (Class)classlist[i];
                Class newCls = readClass(cls, headerIsBundle, headerIsPreoptimized);
    
                if (newCls != cls  &&  newCls) {
                    // Class was moved but not deleted. Currently this occurs 
                    // only when the new class resolved a future class.
                    // Non-lazily realize the class below.
                    resolvedFutureClasses = (Class *)
                        realloc(resolvedFutureClasses, 
                                (resolvedFutureClassCount+1) * sizeof(Class));
                    resolvedFutureClasses[resolvedFutureClassCount++] = newCls;
                }
            }
        }
    

    2、readClass 分析

    由上可以得到 cls 和 类名 关联起来..

    image.png

    增加条件判断--指定判断类

    image.png
    这个if语句肯定不会走的
        if (headerIsPreoptimized  &&  !replacing) {
            // class list built in shared cache
            // fixme strict assert doesn't work because of duplicates
            // ASSERT(cls == getClass(name));
            ASSERT(getClassExceptSomeSwift(mangledName));
        } else {
    
     那直接来到了这里了..
            addNamedClass(cls, mangledName, replacing);
            addClassTableEntry(cls);
        }
    

    addNamedClass,给了cls名字

    image.png

    3、addNamedClass 方法分析

    static void addNamedClass(Class cls, const char *name, Class replacing = nil)
    {
        runtimeLock.assertLocked();
        Class old;
        if ((old = getClassExceptSomeSwift(name))  &&  old != replacing) {
            inform_duplicate(name, old, cls);
    
            // getMaybeUnrealizedNonMetaClass uses name lookups.
            // Classes not found by name lookup must be in the
            // secondary meta->nonmeta table.
            addNonMetaClass(cls);
        } else {
            NXMapInsert(gdb_objc_realized_classes, name, cls);
        }
        ASSERT(!(cls->data()->flags & RO_META));
    
        // wrong: constructed classes are already realized when they get here
        // ASSERT(!cls->isRealized());
    }
    
    image.png

    走完NXMapInsert方法之后,这个类名就关联起来了~

    二、懒加载类与非懒加载类

    懒加载类与非懒加载类的区别:当前类是否实现load方法(load方法在mian函数之前)

    1、非懒加载类情况

    map_images的时候 加载所有类数据:

    • _getObjc2NonlazyClassList
    • readClass
    • realizeClassWithoutSwift
    • methodizeClass
    image.png

    们也可以根据_read_images中的注释分析 ,当我们调试的时候没有走到这里,说明我们没有实现load,要是我们实现load的话是不是在这里就可以观察类的加载情况呢?

    image.png image.png image.png

    读取classdata数据,并将其强转为ro,以及rw初始化ro拷贝一份到rw中的ro

    • ro 表示 readOnly,即只读,其在编译时就已经确定了内存,包含类名称、方法、协议和实例变量的信息,由于是只读的,所以属于Clean Memory,而Clean Memory是指加载后不会发生更改的内存

    • rw 表示 readWrite,即可读可写,由于其动态性,可能会往类中添加属性、方法、添加协议,在最新的2020的WWDC的对内存优化的说明Advancements in the Objective-C runtime - WWDC 2020 - Videos - Apple Developer中,提到rw,其实在rw中只有10%的类真正的更改了它们的方法,所以有了rwe,即类的额外信息。对于那些确实需要额外信息的类,可以分配rwe扩展记录中的一个,并将其滑入类中供其使用。其中rw就属于dirty memory,而 dirty memory是指在进程运行时会发生更改的内存类结构一经使用就会变成 ditry memory,因为运行时会向它写入新数据,例如 创建一个新的方法缓存,并从类中指向它

    我们通过断点调试,发现他走的是 realizeClassWithoutSwift(cls, nil); (实现类)

    image.png image.png

    递归调用realizeClassWithoutSwift完善继承链,并设置当前类、父类、元类的rw
    递归调用 realizeClassWithoutSwift设置父类元类
    设置父类和元类的isa指向
    通过addSubclassaddRootClass设置父子的双向链表指向关系,即父类中可以找到子类,子类中可以找到父类

    image.png
    2、懒加载类情况

    数据加载推迟到第⼀次消息的时候

    • LookUpImpOrForword
    • realizeClassMaybeSwiftMaybeRelock
    • realizeClassWithoutSwift
    • methodizeClass

    我们知道非懒加载怎么加的方法属性。那么懒加载呢?(把load去掉,然后调用一波),我们可以通过bt,或者 看堆栈

    image.png

    总结:

    image.png

    相关文章

      网友评论

          本文标题:12、类的加载分析

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