美文网首页
Runtime 初始化流程

Runtime 初始化流程

作者: yizhaorong | 来源:发表于2017-12-01 13:44 被阅读331次

    初始化函数

    Runtime 的由系统调用 _objc_init 进行初始化化

    图片.png
    void _objc_init(void)
    {
        // 标记是否已初始化
        static bool initialized = false;
        if (initialized) return;
        initialized = true;
        
        // fixme defer initialization until an objc-using image is found?
        // 读取环境变量,并且可以在里面开启打印选项,方便调式
        environ_init();
        // 初始化线程信息
        tls_init();
        // 初始化 C++ 静态构造方法
        static_init();
        lock_init();
        // 初始化异常处理系统
        exception_init();
        // 注册镜像映射、加载镜像、卸载镜像映射
        _dyld_objc_notify_register(&map_images, load_images, unmap_image);
    }
    

    一、environ_init

    读取环境配置方法,在这个方法里会读取在Xcode 中配置的环境变量参数。如图:

    图片.png
    可配置环境变量可以参见头文件 objc-env.h
    // -*- truncate-lines: t; -*-
    
    // OPTION(var, env, help)
    
    OPTION( PrintImages,              OBJC_PRINT_IMAGES,               "log image and library names as they are loaded")
    OPTION( PrintImageTimes,          OBJC_PRINT_IMAGE_TIMES,          "measure duration of image loading steps")
    OPTION( PrintLoading,             OBJC_PRINT_LOAD_METHODS,         "log calls to class and category +load methods")
    OPTION( PrintInitializing,        OBJC_PRINT_INITIALIZE_METHODS,   "log calls to class +initialize methods")
    OPTION( PrintResolving,           OBJC_PRINT_RESOLVED_METHODS,     "log methods created by +resolveClassMethod: and +resolveInstanceMethod:")
    OPTION( PrintConnecting,          OBJC_PRINT_CLASS_SETUP,          "log progress of class and category setup")
    OPTION( PrintProtocols,           OBJC_PRINT_PROTOCOL_SETUP,       "log progress of protocol setup")
    OPTION( PrintIvars,               OBJC_PRINT_IVAR_SETUP,           "log processing of non-fragile ivars")
    OPTION( PrintVtables,             OBJC_PRINT_VTABLE_SETUP,         "log processing of class vtables")
    OPTION( PrintVtableImages,        OBJC_PRINT_VTABLE_IMAGES,        "print vtable images showing overridden methods")
    OPTION( PrintCaches,              OBJC_PRINT_CACHE_SETUP,          "log processing of method caches")
    OPTION( PrintFuture,              OBJC_PRINT_FUTURE_CLASSES,       "log use of future classes for toll-free bridging")
    OPTION( PrintPreopt,              OBJC_PRINT_PREOPTIMIZATION,      "log preoptimization courtesy of dyld shared cache")
    OPTION( PrintCxxCtors,            OBJC_PRINT_CXX_CTORS,            "log calls to C++ ctors and dtors for instance variables")
    OPTION( PrintExceptions,          OBJC_PRINT_EXCEPTIONS,           "log exception handling")
    OPTION( PrintExceptionThrow,      OBJC_PRINT_EXCEPTION_THROW,      "log backtrace of every objc_exception_throw()")
    OPTION( PrintAltHandlers,         OBJC_PRINT_ALT_HANDLERS,         "log processing of exception alt handlers")
    OPTION( PrintReplacedMethods,     OBJC_PRINT_REPLACED_METHODS,     "log methods replaced by category implementations")
    OPTION( PrintDeprecation,         OBJC_PRINT_DEPRECATION_WARNINGS, "warn about calls to deprecated runtime functions")
    OPTION( PrintPoolHiwat,           OBJC_PRINT_POOL_HIGHWATER,       "log high-water marks for autorelease pools")
    OPTION( PrintCustomRR,            OBJC_PRINT_CUSTOM_RR,            "log classes with un-optimized custom retain/release methods")
    OPTION( PrintCustomAWZ,           OBJC_PRINT_CUSTOM_AWZ,           "log classes with un-optimized custom allocWithZone methods")
    OPTION( PrintRawIsa,              OBJC_PRINT_RAW_ISA,              "log classes that require raw pointer isa fields")
    
    OPTION( DebugUnload,              OBJC_DEBUG_UNLOAD,               "warn about poorly-behaving bundles when unloaded")
    OPTION( DebugFragileSuperclasses, OBJC_DEBUG_FRAGILE_SUPERCLASSES, "warn about subclasses that may have been broken by subsequent changes to superclasses")
    OPTION( DebugNilSync,             OBJC_DEBUG_NIL_SYNC,             "warn about @synchronized(nil), which does no synchronization")
    OPTION( DebugNonFragileIvars,     OBJC_DEBUG_NONFRAGILE_IVARS,     "capriciously rearrange non-fragile ivars")
    OPTION( DebugAltHandlers,         OBJC_DEBUG_ALT_HANDLERS,         "record more info about bad alt handler use")
    OPTION( DebugMissingPools,        OBJC_DEBUG_MISSING_POOLS,        "warn about autorelease with no pool in place, which may be a leak")
    OPTION( DebugPoolAllocation,      OBJC_DEBUG_POOL_ALLOCATION,      "halt when autorelease pools are popped out of order, and allow heap debuggers to track autorelease pools")
    OPTION( DebugDuplicateClasses,    OBJC_DEBUG_DUPLICATE_CLASSES,    "halt when multiple classes with the same name are present")
    OPTION( DebugDontCrash,           OBJC_DEBUG_DONT_CRASH,           "halt the process by exiting instead of crashing")
    
    OPTION( DisableVtables,           OBJC_DISABLE_VTABLES,            "disable vtable dispatch")
    OPTION( DisablePreopt,            OBJC_DISABLE_PREOPTIMIZATION,    "disable preoptimization courtesy of dyld shared cache")
    OPTION( DisableTaggedPointers,    OBJC_DISABLE_TAGGED_POINTERS,    "disable tagged pointer optimization of NSNumber et al.") 
    OPTION( DisableNonpointerIsa,     OBJC_DISABLE_NONPOINTER_ISA,     "disable non-pointer isa fields")
    
    

    二、tls_init

    用于初始化不是使用pthread_key_create()创建的线程的析构函数。

    void tls_init(void)
    {
        // 支持线程
    #if SUPPORT_DIRECT_THREAD_KEYS
        _objc_pthread_key = TLS_DIRECT_KEY;
        // 设置线程析构函数
        pthread_key_init_np(TLS_DIRECT_KEY, &_objc_pthread_destroyspecific);
    #else
        _objc_pthread_key = tls_create(&_objc_pthread_destroyspecific);
    #endif
    }
    

    三、static_init

    方法实现执行 C++ 静态构造函数功能

    /***********************************************************************
    * static_init
    * Run C++ static constructor functions.
    * libc calls _objc_init() before dyld would call our static constructors, 
    * so we have to do it ourselves.
    **********************************************************************/
    static void static_init()
    {
        size_t count;
        // 获取所有构造器
        Initializer *inits = getLibobjcInitializers(&_mh_dylib_header, &count);
        // 执行静态构造函数
        for (size_t i = 0; i < count; i++) {
            inits[i]();
        }
    }
    

    四、lock_init

    编码后台线程和主线程优先级。

    void lock_init(void)
    {
    #if SUPPORT_QOS_HACK
        // 将类优先级对编码为线程优先级
        BackgroundPriority = _pthread_qos_class_encode(QOS_CLASS_BACKGROUND, 0, 0);
        MainPriority = _pthread_qos_class_encode(qos_class_main(), 0, 0);
    # if DEBUG
        pthread_key_init_np(QOS_KEY, &destroyQOSKey);
    # endif
    #endif
    }
    

    五、_dyld_objc_notify_register

    注册镜像映射、加载镜像、卸载镜像映射,此方法涉及类的加载,初始化过程。

    1. map_images

    进入方法后,先进行加锁,后后转到map_images_nolock方法进行处理

    1.1 map_images_nolock

    方法内实现共享内存优化,默认方法注册、自动释放池和散列表初始化及类的加载等操作。方法比较长,关键代码如下:

        if (firstTime) {
            // 共享内存优化
            preopt_init();
        }
    
        if (firstTime) {
            // 注册默认方法(load等)
            sel_init(selrefCount);
            // 自动释放池和散列表初始化
            arr_init();
        }
    
        if (hCount > 0) {
            // 类加载、方法注册、分类加载、协议加载等操作
            _read_images(hList, hCount, totalClasses, unoptimizedTotalClasses);
        }
    

    方法主体完成默认方法注册和自动释放池和散列表初始化后将操作转到_read_images,进行类的相关操作。

    1.2 _read_images

    方法内实现类加载,方法注册,加载虚函数表,加载协议Protocol,非延迟类方法和静态实例加载
    加载分类

    # 类加载
    classref_t *classlist = _getObjc2ClassList(hi, &count);
    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;
        }
    }
    
    # 方法注册
    SEL *sels = _getObjc2SelectorRefs(hi, &count);
    UnfixedSelectors += count;
    for (i = 0; i < count; i++) {
        const char *name = sel_cname(sels[i]);
        sels[i] = sel_registerNameNoLock(name, isBundle);
    }
    
    # 加载虚函数表
    message_ref_t *refs = _getObjc2MessageRefs(hi, &count);
    if (count == 0) continue;
    
    if (PrintVtables) {
        _objc_inform("VTABLES: repairing %zu unsupported vtable dispatch "
                     "call sites in %s", count, hi->fname());
    }
    for (i = 0; i < count; i++) {
        fixupMessageRef(refs+i);
    }
    
    # 加载协议
    protocol_t **protolist = _getObjc2ProtocolList(hi, &count);
    for (i = 0; i < count; i++) {
        readProtocol(protolist[i], cls, protocol_map, 
                     isPreoptimized, isBundle);
    }
    
    # 实现非延迟类方法和静态实例加载
    classref_t *classlist = _getObjc2NonlazyClassList(hi, &count);
    for (i = 0; i < count; i++) {
        Class cls = remapClass(classlist[i]);
        if (!cls) continue;
    
        // hack for class __ARCLite__, which didn't get this above
    #if TARGET_OS_SIMULATOR
        if (cls->cache._buckets == (void*)&_objc_empty_cache  &&  
            (cls->cache._mask  ||  cls->cache._occupied)) 
        {
            cls->cache._mask = 0;
            cls->cache._occupied = 0;
        }
        if (cls->ISA()->cache._buckets == (void*)&_objc_empty_cache  &&  
            (cls->ISA()->cache._mask  ||  cls->ISA()->cache._occupied)) 
        {
            cls->ISA()->cache._mask = 0;
            cls->ISA()->cache._occupied = 0;
        }
    #endif
    
        realizeClass(cls);
    }
    
    # 加载分类 categories
    bool hasClassProperties = hi->info()->hasCategoryClassProperties();
    
    for (i = 0; i < count; i++) {
        category_t *cat = catlist[i];
        Class cls = remapClass(cat->cls);
        // ... 加载逻辑
    }
    

    2. load_images

    判断是否有实现load方法,如果实现了,则进行加锁,调用load方法预处理,调用load方法

    2.1 prepare_load_methods

    预处理类的load方法和分类的load方法

    runtimeLock.assertWriting();
    
    classref_t *classlist = 
        _getObjc2NonlazyClassList(mhdr, &count);
    for (i = 0; i < count; i++) {
        // 预处理类的load方法
        schedule_class_load(remapClass(classlist[i]));
    }
    
    // 预处理分类的load方法
    category_t **categorylist = _getObjc2NonlazyCategoryList(mhdr, &count);
    for (i = 0; i < count; i++) {
        category_t *cat = categorylist[i];
        Class cls = remapClass(cat->cls);
        if (!cls) continue;  // category for ignored weak-linked class
        realizeClass(cls);
        assert(cls->ISA()->isRealized());
        add_category_to_loadable_list(cat);
    }
    

    2.3 call_load_methods

    调用类和分类的load方法

    void call_load_methods(void)
    {
        static bool loading = NO;
        bool more_categories;
    
        loadMethodLock.assertLocked();
    
        // Re-entrant calls do nothing; the outermost call will finish the job.
        // 正在执行则返回
        if (loading) return;
        loading = YES;
        // 创建自动释放池
        void *pool = objc_autoreleasePoolPush();
    
        do {
            // 1. Repeatedly call class +loads until there aren't any more
            // 1. 循环调用load方法,直到完成所有调用为止
            while (loadable_classes_used > 0) {
                call_class_loads();
            }
    
            // 2. Call category +loads ONCE
            // 2. 调用一次分类的load方法
            more_categories = call_category_loads();
    
            // 3. Run more +loads if there are classes OR more untried categories
            // 3. 完成所有分类的load加载
        } while (loadable_classes_used > 0  ||  more_categories);
        // 释放自动释放池
        objc_autoreleasePoolPop(pool);
        // 重置状态
        loading = NO;
    }
    

    六、unmap_image

    此方法只是在初始化时注册,并未执行,用于执行卸载镜像

    相关文章

      网友评论

          本文标题:Runtime 初始化流程

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