iOS App启动原理

iOS App启动原理

在工程中可以看到main函数是程序的入口,其实在启动之前系统做了很多的工作,比如fork子进程,调用exec函数等,app的启动离不开系统内核的支持,所以在这之前需要对iOS系统架构有个基本了解

iOS系统简介

Mac系统是基于Unix内核的图形化操作系统,Mac OSiOS系统架构层只有最上面的应用层框架部分有区别,Mac使用的是Cocoa框架, 而iOSCocoa Toouch框架,其余层的架构都是一样的

应用层
应用层基础框架
核心框架层
Drawin框架层
  • 应用层: 手机上的图形应用,如Spotlight,SprintBoard
  • 应用层框架: Cocoa框架,包括 Foundation,ApplicationKit,UIKit等,从功能上主要表现为系统ui,网络,文件存储,以及系统服务,他们大都基于核心框架层封装而来
  • 核心框架层: 各种Core开头的framework,CoreMedia,CoreAnimation,CoreGraphics,OpenGL,CoreFoundataion…
  • Drawin层: 这部分是操作系统的核型,包括kernel,dirivers,bsd等

Nac OX系统是又BSDMach所改写的一个混合内核,名字叫Drawin的操作系统,符合POSIX标准的UNIX和行. Mach是苹果自研的为内核操作系统,主要包括进程调度管理,内存管理,而I/O操作,网络文件等则由开源的BSD系统适配而来,通过LibSystem库可以访问到哦这些和行功能.

程序启动

这里把从应用图标被用户点击到app,到app进入前台,声明周期变为active状态统称为启动前

Ready
MachO
dyld
Objc
Intializers
main
launch
  • Objc
读取DATA段
注册Objc
Selector唯一性
读取Prootocol
读取Category
  • Initializers

初始化C++构造函数,以及静态对象加载

主程序的MachO文件由内核加载,之后dyld会负责动态库的加载,dyld根据MachO文件中Load Commands找到置顶的恶LC_LOAD_DYLIB,将相关的dylib加载到进程的空间

结合图例,分为以下这几个步骤:

  1. 系统为程序启动做准备,初始化进程资源
  2. 加载主程序的MachO并将控制权交给dyld
  3. dyld递归的加载程序所需要的动态库
  4. dyld对程序进程相关的依赖库进行rebase和binding操作,最终实现程序内部符号和三方库之间的绑定
  5. objc setup,objc的load调用,方法,协议,分类创建
  6. 运行初初始化函数,主要是C++构造函数和静态对象
  7. 执行main函数,应用程序入口,开启mainRunLoop,创建appDelegate
  8. 应用程序启动完成调用AppDelegate的didFinishLaunch方法

从pre-main之前可以看出,下面这些因子会严重拉胯程序的启动时间

  1. 动态库加载越多,启动越慢。
  2. ObjC类越多,启动越慢
  3. C的constructor函数越多,启动越慢
  4. C++静态对象越多,启动越慢
  5. ObjC的+load越多,启动越慢

dyld动态库加载器

源码: https://opensource.apple.com/tarballs/dyld/,这里有多个版本

  • 终端执行man dyld可以看到它的一些基本说名,它是系统的动态链接器,将外部动态库与主程序关联,完成他们之间的符号绑定

dyld_info 查找dyld的信息
dyld_usage 可以查找dyld的各项指标

  • dyldlibobjc库加载后,开始初始化images中全局的构造函数,libobjc.A.dylib对应的image会调用_objc_init,注册dyld的map_images, load_images事件
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 11.1
  * frame #0: 0x00000001007e7734 libobjc.A.dylib`_objc_init at objc-os.mm:926:9
    frame #1: 0x00000001005a8553 libdispatch.dylib`_os_object_init + 13
    frame #2: 0x00000001005b9d77 libdispatch.dylib`libdispatch_init + 311
    frame #3: 0x00007ff823fd2898 libSystem.B.dylib`libSystem_initializer + 238
    frame #4: 0x0000000100028ddb dyld`invocation function for block in dyld4::Loader::findAndRunAllInitializers(dyld4::RuntimeState&) const + 182
    frame #5: 0x000000010004f257 dyld`invocation function for block in dyld3::MachOAnalyzer::forEachInitializer(Diagnostics&, dyld3::MachOAnalyzer::VMAddrConverter const&, void (unsigned int) block_pointer, void const*) const + 242
    frame #6: 0x000000010004685a dyld`invocation function for block in dyld3::MachOFile::forEachSection(void (dyld3::MachOFile::SectionInfo const&, bool, bool&) block_pointer) const + 557
    frame #7: 0x0000000100015db3 dyld`dyld3::MachOFile::forEachLoadCommand(Diagnostics&, void (load_command const*, bool&) block_pointer) const + 129
    frame #8: 0x00000001000465eb dyld`dyld3::MachOFile::forEachSection(void (dyld3::MachOFile::SectionInfo const&, bool, bool&) block_pointer) const + 179
    frame #9: 0x000000010004edae dyld`dyld3::MachOAnalyzer::forEachInitializer(Diagnostics&, dyld3::MachOAnalyzer::VMAddrConverter const&, void (unsigned int) block_pointer, void const*) const + 466
    frame #10: 0x0000000100028d0e dyld`dyld4::Loader::findAndRunAllInitializers(dyld4::RuntimeState&) const + 144
    frame #11: 0x000000010003c496 dyld`dyld4::APIs::runAllInitializersForMain() + 38
    frame #12: 0x000000010001a37d dyld`dyld4::prepare(dyld4::APIs&, dyld3::MachOAnalyzer const*) + 3443
    frame #13: 0x00000001000194d4 dyld`start + 388

objc_init初始化主要开辟objc相关的内存空间和dyld的load_images绑定函数

void _objc_init(void)
{
    static bool initialized = false;
    if (initialized) return;
    initialized = true;
    
    // fixme defer initialization until an objc-using image is found?
    // 初始化环境变量Objc的环境变量,设置`OBJC_HELP=1`可以打印所有相关的环境变量
    environ_init();
    // 绑定线程的key,用于在线程结束时释放key所对应的内存块
    tls_init();
    // 运行C++的静态构造函数,在dyld调用静态构造函数之前,libc调用`_objc_init`
    static_init();
    // Runtime运行时初始化,分别是类表和分类表的初始化
    runtime_init();
    // 初始化libobjc的异常处理系统。
    exception_init();
#if __OBJC2__
    // 为当前的任务注册一段属于当前任务的可重启的缓存空间范围
    cache_t::init();
#endif
    // 在mac上才有用,启动回调机制,以及在某些进程加载trampolines.dylib
    _imp_implementationWithBlock_init();
    
    // 注册dyld的对image的操作事件执行相应的操作,如加载未载入的分类,加载所有类的`+load`方法
    _dyld_objc_notify_register(&map_images, load_images, unmap_image);
   
}
  • dyld在image加载完成之后触发objc_init注册的回调函数,执行objc相关的设置,+load和分类+load,以及方法选择器唯一性修复
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 5.1
  * frame #0: 0x00000001043a3f70 ObjectiveCLuanch`+[ViewController load](self=ViewController, _cmd="load") at ViewController.mm:21:5
    frame #1: 0x000000010490a517 libobjc.A.dylib`load_images + 1233 //读取objc相关的section
    frame #2: 0x00000001045c7de8 dyld_sim`dyld4::RuntimeState::notifyObjCInit(dyld4::Loader const*) + 170 //当动态库加载完成后通过objc的勾子函数
    frame #3: 0x00000001045ccab7 dyld_sim`dyld4::Loader::runInitializersBottomUp(dyld4::RuntimeState&, dyld3::Array<dyld4::Loader const*>&) const + 179
    frame #4: 0x00000001045ccb60 dyld_sim`dyld4::Loader::runInitializersBottomUpPlusUpwardLinks(dyld4::RuntimeState&) const + 102
    frame #5: 0x00000001045dbb5a dyld_sim`dyld4::APIs::runAllInitializersForMain() + 222 //执行相关的初始化函数为运行程序main函数做准备
    frame #6: 0x00000001045bf9fe dyld_sim`dyld4::prepare(dyld4::APIs&, dyld3::MachOAnalyzer const*) + 2528
    frame #7: 0x00000001045bfe42 dyld_sim`_dyld_sim_prepare + 379
    frame #8: 0x000000010c84db68 dyld`dyld4::prepareSim(dyld4::RuntimeState&, char const*) + 1265
    frame #9: 0x000000010c84c6fe dyld`dyld4::prepare(dyld4::APIs&, dyld3::MachOAnalyzer const*) + 244
    frame #10: 0x000000010c84c4d4 dyld`start + 388
load_images(const char *path __unused, const struct mach_header *mh)
{
    if (!didInitialAttachCategories && didCallDyldNotifyRegister) {
        didInitialAttachCategories = true;
        loadAllCategories();
    }

    // Return without taking locks if there are no +load methods here.
    if (!hasLoadMethods((const headerType *)mh)) return;

    recursive_mutex_locker_t lock(loadMethodLock);

    // Discover load methods
    {
        mutex_locker_t lock2(runtimeLock);
        prepare_load_methods((const headerType *)mh);
    }

    // Call +load methods (without runtimeLock - re-entrant)
    call_load_methods();
}
  • 在objc设置完成之后接着执行 C++构造函数,下面是通过__attribute__((contructor))定义的构造函数
 thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 4.1
  * frame #0: 0x00000001043a3f44 ObjectiveCLuanch`permaind() at ViewController.mm:11:5
    frame #1: 0x00000001045cc9f7 dyld_sim`invocation function for block in dyld4::Loader::findAndRunAllInitializers(dyld4::RuntimeState&) const + 182
    frame #2: 0x00000001045e9291 dyld_sim`invocation function for block in dyld3::MachOAnalyzer::forEachInitializer(Diagnostics&, dyld3::MachOAnalyzer::VMAddrConverter const&, void (unsigned int) block_pointer, void const*) const + 242
    frame #3: 0x00000001045e258c dyld_sim`invocation function for block in dyld3::MachOFile::forEachSection(void (dyld3::MachOFile::SectionInfo const&, bool, bool&) block_pointer) const + 555
    frame #4: 0x00000001045e16e9 dyld_sim`dyld3::MachOFile::forEachLoadCommand(Diagnostics&, void (load_command const*, bool&) block_pointer) const + 129
    frame #5: 0x00000001045e231f dyld_sim`dyld3::MachOFile::forEachSection(void (dyld3::MachOFile::SectionInfo const&, bool, bool&) block_pointer) const + 179
    frame #6: 0x00000001045e8de8 dyld_sim`dyld3::MachOAnalyzer::forEachInitializer(Diagnostics&, dyld3::MachOAnalyzer::VMAddrConverter const&, void (unsigned int) block_pointer, void const*) const + 466
    frame #7: 0x00000001045cc92a dyld_sim`dyld4::Loader::findAndRunAllInitializers(dyld4::RuntimeState&) const + 144
    frame #8: 0x00000001045ccac2 dyld_sim`dyld4::Loader::runInitializersBottomUp(dyld4::RuntimeState&, dyld3::Array<dyld4::Loader const*>&) const + 190
    frame #9: 0x00000001045ccb60 dyld_sim`dyld4::Loader::runInitializersBottomUpPlusUpwardLinks(dyld4::RuntimeState&) const + 102
    frame #10: 0x00000001045dbb5a dyld_sim`dyld4::APIs::runAllInitializersForMain() + 222
    frame #11: 0x00000001045bf9fe dyld_sim`dyld4::prepare(dyld4::APIs&, dyld3::MachOAnalyzer const*) + 2528
    frame #12: 0x00000001045bfe42 dyld_sim`_dyld_sim_prepare + 379
    frame #13: 0x000000010c84db68 dyld`dyld4::prepareSim(dyld4::RuntimeState&, char const*) + 1265
    frame #14: 0x000000010c84c6fe dyld`dyld4::prepare(dyld4::APIs&, dyld3::MachOAnalyzer const*) + 244
    frame #15: 0x000000010c84c4d4 dyld`start + 388

程序入口

在上面的操作完成之后开始进入程序入口的main函数.这里会调用UIApplicationMain,创建UIApplication,并开启一个runLoop循环,同时设置Application的代理AppDelegate来代理应用程序的主要声明周期事件.

c
a
b
3.delegate
6.sends
1.call
4.load
2.create
5.createAndManages
7.createsAndDisplays
MainRunLoop
ApplicationWindow
RootViewController
Info.plist
UIApplicationMain
main
AppDelegate
UIApplication
application:didFinishLaunching:withWithOptions:

显示第一帧显示

接下来就是显示视图

 loadView 
 viewDidLoad 
 layoutSubviews
 viewWillAppear
 viewDidAppear ---->此时界面对用户可见

AppLaunch

https://devstreaming-cdn.apple.com/videos/wwdc/2019/423lzf3qsjedrzivc7/423/423_optimizing_app_launch.pdf?dl=1
https://devstreaming-cdn.apple.com/videos/wwdc/2022/110362/3/629CBACC-AF8F-4856-98CA-075275ADEAA4/downloads/wwdc2022-110362_sd.mp4?dl=1
https://developer.apple.com/library/archive/documentation/Darwin/Conceptual/KernelProgramming/Architecture/Architecture.html#//apple_ref/doc/uid/TP30000905-CH1g-CACDAEDC
https://opensource.apple.com/tarballs/objc4/
https://opensource.apple.com/tarballs/dyld/
https://github.com/LGCooci/KCCbjc4_debug

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值