iOS App编译和启动原理

编译原理:

将编译过程分为前端和后端两部分处理

Clang(编译器前端):GCC的替代品,Clang的编译速度比GCC快

1.Lexer:读入源文件,并将其转化成字符流

2.Parser:将字符流转换成AST(抽象语法树)

3.SemanticAnalysis:对输入的AST进行语法检查

4. Code Generation:代码生成,将AST转换成低层次的IR指令

LLVM(编译器后端):底层虚拟机(Low Level Virtual Machine)

1.Optimization:分析IR指令,将其中潜在会拖慢运行速度的指令干掉

2. AsmPrinter:通过IR(中间码)生成特定CPU架构的汇编代码

3.Assemble :将汇编代码转化成机器码

4. Linker:将机器码链接成可执行程序或动态码


iOS App编译和启动原理_第1张图片

BitCode

当我们提交程序到App Store上时,Xcode会将程序编译为一个中间表现形式( bitcode )。然后App store 会再将这个bitcode编译为可执行的64位或32位程序

BitCode是什么?

BitCode类似于一个中间码,被上传到appStore之后,苹果会根据下载应用的用户的手机指令集类型生成只有该指令集的二进制进行下发,从而达到精简安装包体积的目的


iOS App编译和启动原理_第2张图片

指令集

iOS模拟器没有arm指令集,编译运行的是x86/i386指令集

模拟器的指令集:

4S:-5i386

5S以上:X64_86

真机(iOS设备)的默认指令集:

armv6设备:iPhone,iPhone2,iPhone3G

armv7设备:iPhone3GS,iPhone4,iPhone4S

armv7s设备:iPhone5,iPhone5C

arm64设备:iPhone5S以上

但是我们在编译的时候偶尔会报出i386,x86_64的错误?


iOS App编译和启动原理_第3张图片

解决办法:

查看静态库是否支持i386/x86_64的方法:

1.如果是.a文件:

打开终端,使用lipo -info 静态包地址.a查看

2.如果是framework文件:

cd到framework内部,之后在使用lipo -info xxxFramework查看

启动原理

Apple在2016年的WWDC大会上提到:

建议应用的启动时间控制在400ms之下。并且必须在20s以内完成启动,否则系统会kill掉应用程序。那么话说我们如何知道app的在启动到调用main()方法之前的时间呢?

应用的启动分为Pre-main和mian两部分:

Pre-main时间:从在屏幕上点击app icon开始,到应用执行到main()方法都是属于Pre-main时间

以下就是Pre-main部分


dylib loading time:载入动态库,包括引用的第三方库和自定义的动态库Apple官方建议尽量少使用自定义的动

态库,或者考虑合并多个动态库。

rebase/binding time:重构和绑定,rebase会修正调整处理图像的指针,并且会设置指向绑定(binding)外部的图像指针。(即Rebase修正内部的指针指向,Bind 修正外部指针指向)

ObjC setup time:在Objective-C的运行时(runtime),需要对类(class),类别(category)进行注册以及选择器分配

Initializer time:是执行+initialize方法的时间

查看Pre-main时间的方法:

在iOS10之前的系统中,我们无处得知其中的细节。而在iOS10系统中,可以通过简单在Xcode设置,在控制台就可以打印出Pre-main的具体信息细节,见以下两个截图:


iOS App编译和启动原理_第4张图片


iOS App编译和启动原理_第5张图片

你可能感兴趣的:(iOS App编译和启动原理)