iOS底层原理 12 : 应用程序的加载

iOS底层原理 12 : 应用程序的加载_第1张图片

一、应用程序的加载

APP加载过程:程序启动依次加载dyldlibSystemlibdispathc.dyldlibobjc动态库,最终调用_objc_init()方法,在此方法中Runtime向dyld注册回调函数,加载新的image,执行map_imagesload_imagesimageLoader加载image,调用main函数

二、dyld动态链接器

dyld(the dynamic link editor)是苹果的动态链接器,是苹果操作系统一个重要组成部分,在系统内核做好程序准备工作之后,交由dyld负责余下的工作。

1.dyld的加载过程:
1.环境变量的配置
2.共享缓存 checkSharedRegionDisable()
3.主程序的初始化
4.加入动态库 loadInsertedDylib()
5.link主程序 link(sMainExecutable, sEnv.DYLD_BIND_AT_LAUNCH, true, ImageLoader::RPathChain(NULL, NULL), -1)
6.link动态库 link(image, sEnv.DYLD_BIND_AT_LAUNCH, true, ImageLoader::RPathChain(NULL, NULL), -1)
7.initializeMainExecutable运行所有初始化程序
8.main notifyMonitoringDyldMain()

iOS底层原理 12 : 应用程序的加载_第2张图片

2.reloadAllImages加载镜像文件的步骤:

  • 实例化主程序instantiateFromLoadedImage(),内核会映射到主要可执行文件中,我们需要为映射到主可执行文件的文件,创建ImageLoader。在此方法中,然后读取image,然后addImage()读取加载镜像文件。会先在instantiateMainExecutable()中,会确认此mach-o文件中是否具有压缩的LINKEDIT以及段数。
  • 加载插入任何动态库loadInsertedDylib(*lib),将其读取为镜像文件iamge。
  • 链接库。先遍历,读取image,然后link。在link中,递归插入动态加载的镜像文件。

3.initializeMainExecutable()运行所有初始化程序步骤:

  • runInitializers()
  • processInitializers初始化准备。
  • processInitializers中,遍历iamge.count,递归一个个开始初始化条件images[i]->recursiveInitialization
  • 在递归开始初始化条件中recursiveInitialization,通过notifySingle方法,对单个镜像通知开始初始化。获取镜像文件的真实地址(*sNotifyObjCInit)(image->getRealPath(), image->machHeader()), 而notifySingle中的sNotifyObjCInit是在objc_init()中注册传递过来的,所以只有当objc_init()调用时,重新加载image
  • notifySingle方法之后,遍历初始化this->doInitialization(context)
  • 在doInitialization方法中,先调用doImageInit(context),确保libSystem库必须提前初始化完成。再调用doModInitFunctions()方法,对 C++和构造函数处理,然后调用libSystem_initializer方法,调用libdispatch_init,调用_os_object_init,最终调用_objc_init方法。
  • _objc_init方法来注册回调函数,重新加载images,执行map_imagesload_imagesimageLoader加载image,调用main函数。

面试题

1.main()之前系统做了哪些工作?

1)dyld 开始将程序二进制文件初始化

2)交由ImageLoader读取 image,其中包含了我们的类,方法等各种符号(Class、Protocol 、Selector、 IMP)

3)由于runtimedyld 绑定了回调,当image加载到内存后,dyld会通知runtime进行处理

4)runtime 接手后调用map_images做解析和处理

5)接下来load_images中调用call_load_methods方法,遍历所有加载进来的Class,按继承层次依次调用Class+load和其他Category+load方法

6)至此 所有的信息都被加载到内存中

7)最后dyld发送调main函数的通知,接下来就是main函数

你可能感兴趣的:(iOS底层原理 12 : 应用程序的加载)