app加载分析
我们知道app加载其实是依赖许多的底层库的,库是可执行的代码的而二进制文件,当加载的时候就会被操作系统写入到内存中。库分为静态库(.a、.lib)和动态库(framework)
静态库和动态库区别
首先我们看一下编译过程图
编译过程 而动静态库的区别在于他们被编译的顺序 静动态库编译顺序 静态库会被多次编译,而动态库可以做到按需编译,所以动态库可以减少程序在打包后app的体积(占用的内存大小),共享了内存,节约内存资源(eg:UIKit、CoreFoundation、libObjc...)
app启动
app启动过程图上图中image是镜像文件
dyld加载过程
- _dyld_start 连接开始
- uInptr_start(...)应用程序进来 dyld::_main
- 2.1 环境变量相关处理
- 2.2 加载共享缓存
- 2.3 将dlyd本身添加到UUID列表
- 2.4 reloadAllImages
- 2.4.1实例化主程序
- 2.4.2加载任何插入动态库
- 2.4.3连接库
- 2.5 运行所有初始化程序
- 2.6 通知监听dlyd的main
void _objc_init(void)
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();
static_init();
lock_init();
exception_init();
// 保存 - libobjc - dyld
// C++ 怎么去做到通知
// 指针 - 回调 - 函数的地址
// 这里就是我们的数据 - images - objc lib
// dyld
_dyld_objc_notify_register(&map_images, load_images, unmap_image);
}
截屏2020-02-1812.09.54.png
环境变量enviro_init();
void environ_init(void)
{
if (issetugid()) {
// All environment variables are silently ignored when setuid or setgid
// This includes OBJC_HELP and OBJC_PRINT_OPTIONS themselves.
return;
}
...
...
for (size_t i = 0; i < sizeof(Settings)/sizeof(Settings[0]); i++) {
const option_t *opt = &Settings[i];
// if (PrintHelp) _objc_inform("%s: %s", opt->env, opt->help);
//去掉if (PrintHelp)打印判断,可以看到好多环境变量
_objc_inform("%s: %s", opt->env, opt->help);
if (PrintOptions && *opt->var) _objc_inform("%s is set", opt->env);
}
}
}
注销上面标注的代码进行打印,可以看到lldb中的具体内容;如下
环境变量命遍历打印 这里的environ_init()函数负责环境的初始化,里面可以打印我们日常需要的调试数据,eg:OBJC_PRINT_LOAD_METHODS;那么如何使用呢?打开editScheme - 在debug模式下选择Arguments - 点击+号添加:OBJC_PRINT_LOAD_METHODS选择YES:如下图
然后重新跑一遍程序,查看打印。你可以看到所有load的方法
map_Images&Load_Images
将在下一章详细探究map_Images&Load_Images
截屏2020-02-1720.04.01.pngmap_Images
Load_Images
总结
APP启动过程
- APP启动
- 加载libSystem
- Runtime向dyld注册回调函数
- 加载新的image
- 执行map_images、load_images
- 调用main函数
网友评论