程序加载时,会加载静态库、动态库和二进制可执行文件等,由此引出几个问题:
- 问题1❓:什么是静态库?什么是动态库?二者的区别是什么?
- 问题2❓:app加载流程是怎样的?
当app启动时,系统内核做相应处理后,会交给dyld动态链接器继续处理,即内核态向用户态的切换
此时,dyld会加载相应的动态库,其中包括包含有runtime的动态库libSystem,最终,会调用runtime源码中的void _objc_init(void)
函数,这里具体的加载过程,之后再另行总结整理
runtime加载入口函数
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();//对log日志系统的初始化
tls_init();
static_init();
lock_init();//锁
exception_init();//异常
/*通过dyld动态链接器加载runtime所在的动态库libSystem,Runtime向dyld注册回调函数
使用imageLoader加载新的image镜像加载,会执行对应的回调函数
*/
_dyld_objc_notify_register(&map_images, load_images, unmap_image);
}
- ❗️
image
就是一个二进制文件,包括可执行文件(就是在xcode中Products
文件下的可执行二进制文件,直接点击可以直接运行)和动态库;ImageLoader
就是将image
加载进内存的 - ❗️ 当通过一个叫做
ImageLoader
加载新的image
镜像时,就会调用_dyld_objc_notify_register ()
注册的这三个回调函数中的&map_images
函数和load_images
函数,这三个函数就是runtime向dyld注册的三个回调函数 - ❗️ runtime会不停的递归加载
image
,并且有缓存机制,直至所有的image
加载完成,才会最终执行main
函数
回调函数map_images
map_images
void
map_images(unsigned count, const char * const paths[],
const struct mach_header * const mhdrs[])
{
rwlock_writer_t lock(runtimeLock);
return map_images_nolock(count, paths, mhdrs);
}
- ❗️管理可执行文件和动态库中所有的符号,例如:Class,Protocol,Selector,IMP等,比如说Class类通过一个表进行管理;Protocol进行对象的关联,对Selecotr建立表进行管理
map_images_nolock
if (hCount > 0) {
_read_images(hList, hCount, totalClasses, unoptimizedTotalClasses);//这里读取images
}
_read_images
-
❗️该函数主要功能就是将类、方法、协议存储到对应的哈希表中
- ❗️
realizeClass
初始化类,设置rw、ro - ❗️处理分类,将分类中的方法、协议、属性添加到宿主类中
回调函数load_images
- ❗️该函数主要功能就是把需要执行
+(void)load
方法的类和分类分别添加进loadable_classes
和loadable_categories
这俩个表中