程序启动
- 静态库是直接编译进程序的
- 动态库是需要的时候动态添加的,dyld链接的就是动态库
- dyld 是苹果的动态链接器,每个程序依赖的动态库都需要通过dyld(位于/usr/lib/dyld)一个一个加载到内存。 加载的是镜像文件
- 如果每个程序运行的时候都重复的去加载,势必造成运行缓慢,为了优化启动速度和提高程序性能,就用到了共享缓存机制。所有默认的动态链接库被合并成一个大的缓存文件,放到/System/Library/Caches/com.apple.dyld/目录下,按不同框架分别保存
- 例如iPhone 里面就有dyld_shared_cache_armv7s和dyld_shared_cache_armv64两个文件,如下图所示。
-
- objc_init
- 提供运行时环境
- 程序启动后是如何从dyld到objc_init的?
- 递归初始化 system库(系统库)
- dispatch (调度)
- objc -> objc_init
- objc_init 中进行映射,将镜像文件中的数据映射出来映射到表里
- objc_init
- images
- dyld 与 objc_init 通讯
- 这个镜像文件在dyld 中才有
- objc_init依赖的镜像文件
- 回调函数
- *snotif
- 注册
- 指针
- images 加载
- 在内存中用表存(内存中存的形式集合形式、table表形式,map)
- 镜像文件给读出来 – 存到内存中
- 读的数据都是什么?
- 二进制(类、协议、分类、sel)
类的加载
_objc_init
- 程序在启动时,先用dyld进行动态库的链接,做完一系列准备操作之后,会进入到_objc_init方法
-
/*********************************************************************** * _objc_init * Bootstrap initialization. Registers our image notifier with dyld. * Called by libSystem BEFORE library initialization time **********************************************************************/ 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(); //关于线程key的绑定 static_init(); //系统级别的类,在这里进行初始化 lock_init(); //是空实现!!这个方法里面什么都没写 exception_init(); //初始化libobic的异常处理系统 _dyld_objc_notify_register(&map_images, load_images, unmap_image); //注册处理程序,以便在映射,取消映射和初始化objc图像是调用。 }
1、environ_init
- 读取影响运行时的环境变量,可以在终端输入 export OBJC_HELP=1 来打印环境变量帮助
-
objc[3206]: Objective-C runtime debugging. Set variable=YES to enable. objc[3206]: OBJC_HELP: describe available environment variables objc[3206]: OBJC_PRINT_OPTIONS: list which options are set objc[3206]: OBJC_PRINT_IMAGES: log image and library names as they are loaded objc[3206]: OBJC_PRINT_IMAGE_TIMES: measure duration of image loading steps objc[3206]: OBJC_PRINT_LOAD_METHODS: log calls to class and category +load methods objc[3206]: OBJC_PRINT_INITIALIZE_METHODS: log calls to class +initialize methods objc[3206]: OBJC_PRINT_RESOLVED_METHODS: log methods created by +resolveClassMethod: and +resolveInstanceMethod: objc[3206]: OBJC_PRINT_CLASS_SETUP: log progress of class and category setup objc[3206]: OBJC_PRINT_PROTOCOL_SETUP: log progress of protocol setup objc[3206]: OBJC_PRINT_IVAR_SETUP: log processing of non-fragile ivars objc[3206]: OBJC_PRINT_VTABLE_SETUP: log processing of class vtables objc[3206]: OBJC_PRINT_VTABLE_IMAGES: print vtable images showing overridden methods objc[3206]: OBJC_PRINT_CACHE_SETUP: log processing of method caches
2、tls_init()
- 关于线程key的绑定 – 比如每个线程数量的析构函数
- 析构函数:析构函数(destructor) 与构造函数相反,当对象结束其生命周期,如对象所在的函数已调用完毕时,系统自动执行析构函数。析构函数往往用来做“清理善后” 的工作(例如在建立对象时用new开辟了一片内存空间,delete会自动调用析构函数后释放内存)。
3、static_init()
- 运行C++静态构造函数。在dyld调用我们的静态构造函数之前,“libc”会调用“_objc_init()”,因此我们必须自己做。
- 这个地方一定要比dyld(_dyld_objc_notify_register)靠前,因为这个是系统级别的,所必须要比dyld靠前进行初始化
- 这是系统级别的类,在这里进行初始化。libc在dyld调用静态构造函数之前调用_objc_init(),
-
/*********************************************************************** * static_init * Run C++ static constructor functions. * libc calls _objc_init() before dyld would call our static constructors, libc在dyld调用静态构造函数之前调用_objc_init(), * so we have to do it ourselves. **********************************************************************/ static void static_init() { size_t count; auto inits = getLibobjcInitializers(&_mh_dylib_header, &count); for (size_t i = 0; i < count; i++) { inits[i](); } }
4、lock_init()
- 就是说objc的异常是完券才用C++那一套的 – 本身就是通过C++写的
- 是空实现!!这个方法里面什么都没写
5、_dyld_objc_notify_register
前面的都是准备条件,_dyld_objc_notify_register,通过注释可以知道该方法仅仅只用来在objc的运行时使用 ,进行map_images 和 load_images
_dyld_objc_notify_register(&map_images, load_images, unmap_images)
- 仅供objc运行时使用,objc在这里是运行时环境
- 注册处理程序,以便在映射,取消映射和初始化objc图像是调用。
- dyld将使用包含objc_image_info的镜像文件的数组回调“mapped”函数
- map_images
- 读取镜像文件
- load_images
- unmap_image
- 程序终止、异常等,内存里干掉部分镜像文件
未完 。。。 待续