IT门户网,专注电脑知识与技术及手机硬件信息服务网站!

当前位置:IT门户网 > 系统教程 >

今天头条iOS客户端启动速度优化

时间:2021-09-14    来源:IT门户网    人气:

应用启动时间,直接影响用户对一款应用的判定和利用体验。头条主app自己就包括很是多而且巨大度高的业务模块(如新闻、视频等),也接入了许多第三方的插件,这势必会拖慢应用的启动时间,本着字斟句酌的立场和对用户体验的追求,我们但愿在业务扩张的同时最洪流平的优化启动时间。

技能调研

先说结论,t(App总启动时间) = t1(main()之前的加载时间) + t2(main()之后的加载时间)。 t1 = 系统dylib(动态链接库)和自身App可执行文件的加载; t2 = main要领执行之后到AppDelegate类中的- (BOOL)application:(UIApplication *)Application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions要领执行竣事前这段时间,主要是构建第一个界面,并完成渲染展示。

main()挪用之前的加载进程

App开始启动后, 系统首先加载可执行文件(自身App的所有.o文件的荟萃),然后加载动态链接库dyld,dyld是一个专门用来加载动态链接库的库。 执行从dyld开始,dyld从可执行文件的依赖开始, 递归加载所有的依赖动态链接库。 动态链接库包罗:iOS 顶用到的所有系统 framework,加载OC runtime要领的libobjc,系统级此外libSystem,譬喻libdispatch(GCD)和libsystem_blocks (Block)。

其实无论对付系统的动态链接库照旧对付App自己的可执行文件而言,他们都算是image(镜像),而每个App都是以image(镜像)为单元举办加载的,那么image毕竟包罗哪些呢?

什么是image

1.executable可执行文件 好比.o文件。 2.dylib 动态链接库 framework就是动态链接库和相应资源包括在一起的一个文件夹布局。 3.bundle 资源文件 只能用dlopen加载,不推荐利用这种方法加载。

除了我们App自己的可行性文件,系统中所有的framework好比UIKit、Foundation等都是以动态链接库的方法集成进App中的。

系统利用动态链接有几点长处:

代码共用:许多措施都动态链接了这些 lib,但它们在内存和磁盘中中只有一份。 易于维护:由于被依赖的 lib 是措施执行时才链接的,所以这些 lib 很容易做更新,好比libSystem.dylib 是 libSystem.B.dylib 的替身,哪天想进级直接换成libSystem.C.dylib 然后再替换替身就行了。 淘汰可执行文件体积:对比静态链接,动态链接在编译时不需要打进去,所以可执行文件的体积要小许多。

本日头条iOS客户端启动速度优化

如上图所示,差异历程之间共用系统dylib的_TEXT区,可是各自维护对应的_DATA区。

所有动态链接库和我们App中的静态库.a和所有类文件编译后的.o文件最终都是由dyld(the dynamic link editor),Apple的动态链接器来加载到内存中。每个image都是由一个叫做ImageLoader的类来认真加载(一一对应),那么ImageLoader又是什么呢?

什么是ImageLoader

image 暗示一个二进制文件(可执行文件或 so 文件),内里是被编译过的标记、代码等,所以 ImageLoader 浸染是将这些文件加载进内存,且每一个文件对应一个ImageLoader实例来认真加载。 两步走: 在措施运行时它先将动态链接的 image 递归加载 (也就是上面测试栈中一串的递归挪用的时刻)。 再从可执行文件 image 递归加载所有标记。

虽然所有这些都产生在我们真正的main函数执行前。

动态链接库加载的详细流程

动态链接库的加载步调详细分为5步:

load dylibs image 读取库镜像文件Rebase imageBind imageObjc setupinitializersload dylibs image

在每个动态库的加载进程中, dyld需要:

阐明所依赖的动态库找到动态库的mach-o文件打开文件验证文件在系统焦点注册文件签名对动态库的每一个segment挪用mmap()

凡是的,一个App需要加载100到400个dylibs, 可是个中的系统库被优化,可以很快的加载。 针对这一步调的优化有:

淘汰非系统库的依赖归并非系统库利用静态资源,好比把代码插手主措施rebase/bind

由于ASLR(address space layout randomization)的存在,可执行文件和动态链接库在虚拟内存中的加载地点每次启动都不牢靠,所以需要这2步来修复镜像中的资源指针,来指向正确的地点。 rebase修复的是指向当前镜像内部的资源指针; 而bind指向的是镜像外部的资源指针。 rebase步调先举办,需要把镜像读入内存,并以page为单元举办加密验证,担保不会被改动,所以这一步的瓶颈在IO。bind在其后举办,由于要查询标记表,来指向跨镜像的资源,加上在rebase阶段,镜像已被读入和加密验证,所以这一步的瓶颈在于CPU计较。 通过呼吁行可以查察相关的资源指针:

xcrun dyldinfo -rebase -bind -lazy_bind myApp.App/myApp

优化该阶段的要害在于淘汰__DATA segment中的指针数量。我们可以优化的点有:

淘汰Objc类数量, 淘汰selector数量淘汰C++虚函数数量转而利用swift stuct(其实本质上就是为了淘汰标记的数量)Objc setup

这一步主要事情是:

注册Objc类 (class registration)把category的界说插入要领列表 (category registration)担保每一个selector独一 (selctor uniquing)

由于之前2步调的优化,这一步实际上没有什么可做的。

initializers

相关文章

系统教程排行榜

更多>>

网络知识排行榜

更多>>

系统教程排行榜

更多>>

服务号