L'optimisation du démarrage iOS est suffisante pour me voir

arrière-plan

L'optimisation du démarrage iOS fait référence à une série de technologies et de méthodes permettant d'améliorer la vitesse de démarrage et la réactivité des applications sur les appareils iOS. Avec la popularité des appareils mobiles et la complexité des fonctions d'application, les utilisateurs ont des exigences de plus en plus élevées sur la vitesse de réponse des programmes d'application.Par conséquent, l'optimisation du démarrage est devenue un domaine de préoccupation important pour les développeurs.

En ce qui concerne le démarrage, il s'agit en fait d'un scénario d'expérience utilisateur très important.Au début, certains blogueurs aimaient comparer les différences entre les appareils en comparant le temps qu'il faut à Android et Apple pour ouvrir une certaine application, et jugé par le temps il faut pour démarrer un certain logiciel avantages et inconvénients des deux systèmes.

Bien sûr, cela a également un impact important sur les utilisateurs dans certains scénarios. Prenons un scénario que j'ai rencontré auparavant. J'ai rencontré un ami que je n'avais pas vu depuis de nombreuses années et j'ai accepté d'offrir un dîner à l'autre partie. Quand il était temps pour payer, mon ami s'est également précipité pour payer. À ce moment-là, alors que j'étais sur le point d'ouvrir l'application WeChat pour commencer, elle s'est soudainement bloquée et a finalement demandé à mon ami de payer en premier. N'est-ce pas gênant ?

Cela dit, Apple dispose d'un mécanisme de chien de garde pour un temps de démarrage trop long, si le temps de démarrage est trop long, le chien de garde le terminera, ce qui est également fatal pour les utilisateurs.

En règle générale, les utilisateurs lancent une application plusieurs fois par jour si cela fait partie de leur flux de travail habituel, et les longs délais de lancement entraînent des retards dans l'exécution des tâches.

Lorsque l'utilisateur appuie sur l'icône de l'application sur l'écran d'accueil, iOS se prépare à lancer l'application avant de céder le contrôle au processus d'application. L'application exécute ensuite le code en vue de dessiner son interface utilisateur à l'écran. Même après que l'interface utilisateur de l'application est visible, l'application peut toujours préparer du contenu ou remplacer l'interface utilisateur interstitielle par des contrôles finaux. Chacune de ces étapes affecte le temps de démarrage total perçu de l'application.

démarrer le processus

Commençons par tout le processus de démarrage pour voir ce qui a été fait à la fin

Optimisation du démarrage iOS.png

Divisé en plusieurs grandes étapes

On peut voir qu'il est principalement divisé en les grandes étapes suivantes

1. Charger l'étage Mach-O

2. Stade Dyld

3. Après l'étape principale : chargez l'élément de démarrage dans l'appel final de viewDidAppear pour charger la première image.

Divisé du point de vue de dyld et d'exécution

S'il est combiné avec les deux modules de base de dyld et runtime, la phase de démarrage est principalement complétée par la coopération des deux.

Heure de lancement.webp image2.png

étapes détaillées

Ensuite, le processus global peut être trié dans les étapes suivantes

1. Charger les fichiers mach-o et les fichiers exécutables en mode noyau

À propos des fichiers mach-o

Introduction aux limes Mach-O

  • Mach object的缩写,是Mac、iOS上用于存储程序、库的标准格式 ,Mach-O文件是一种叫法,就像以 .text 结尾的文件,被叫做为text文件

常见的Mach-O文件有:

  • MH_OBJECT:目标文件(.o)、静态库文件(.a) 静态库其实就是N个.o合并在一起
  • MH_EXECUTE:可执行文件 .app/xx
  • MH_DYLIB:动态库文件 .dylib 或 .framework/xx
  • MH_DYLINKER:动态链接编辑器 /usr/lib/dyld
  • MH_DSYM:存储着二进制文件符号信息的文件 .dSYM/Contents/Resources/DWARF/xx(常用于分析APP的崩溃信息)

可执行文件:

  • 平时编写的代码最终会被编译成为一个Mach-O格式的文件
  • 开发过程中所用到的动态库(比如:UIKit、Foundation) 依赖信息也会存储在可执行文件中

二.dyld 阶段

简单介绍下dyld是什么

"dyld" 是苹果操作系统中的一个重要组件,它是动态链接器(dynamic linker)的缩写。动态链接器是操作系统加载和链接可执行文件所需的共享库的核心组件之一。

dyld 的主要功能是在程序启动时加载和链接程序所依赖的共享库,并将其映射到进程的内存空间中。它负责解析和处理共享库之间的符号依赖关系,以及处理运行时的符号重定位。

具体来说,dyld 的工作流程如下:

  1. 加载:当一个可执行文件(如应用程序)启动时,dyld 负责加载可执行文件和它所依赖的共享库到内存中。
  2. 符号解析:dyld 解析可执行文件和共享库中的符号引用,找到对应的符号定义,以便正确地链接和运行程序。
  3. 符号重定位:在加载和链接过程中,dyld 会处理符号重定位,将程序中的符号引用指向正确的地址。
  4. 启动程序:完成加载和链接后,dyld 将控制权转交给程序的入口点,使其开始执行。

dyld 的存在使得应用程序可以动态地加载和链接共享库,从而实现了代码的共享和重用。这也是为什么在 iOS 开发中,我们可以使用各种系统提供的框架和库来构建应用程序。dyld 是苹果操作系统中负责动态加载和链接共享库的组件,它在应用程序启动时发挥着关键的作用,确保程序能够正确地加载和执行所需的代码和库。

关于动态库:

  • 程序运行时由系统动态加载到内存,而不是复制,供程序调用。
  • 系统只加载一次,多个程序共用,节省内存。因此,编译内容更小,而且因为动态库是需要时才被引用,所以更快。 简单认识:系统的UIKit框架最终被dyld以动态库的形式加载到内存 !

dyld阶段所做的事情

Dyld Steps.png

load dylibs > rebase bind > objc(Notify ObjC Runtime) > initializers

1.load dylibs

装载app的可执行文件,同时会递归加载所有依赖的动态库。

  • Parse image(解析图像):在这个步骤中,dyld 解析可执行文件或共享库的二进制格式。它会读取可执行文件的头部和段(segments),以及共享库的符号表和重定位信息等。通过解析图像,dyld 能够了解文件的结构、符号引用和重定位需求。

  • Map image(映射图像):在这一阶段,dyld 将可执行文件或共享库映射到进程的内存空间中。它会分配适当的内存区域,并将二进制文件的内容加载到这些内存区域中。通过映射图像,dyld 将文件中的代码、数据和资源加载到内存,为后续的重定位和符号绑定做准备。

当dyld加载完可执行文件 和动态库 之后通知runtime进行下一步操作。

2.Rebase + bind
  • Rebase image(重定位图像):在此步骤中,dyld 处理可执行文件和共享库中的重定位信息。重定位信息描述了代码和数据的位置相对于内存中的基地址的偏移量。dyld 根据基地址和重定位信息来计算并更新代码和数据的绝对地址,以确保它们在内存中正确定位。

  • Bind image(符号绑定图像):在这个阶段,dyld 解析可执行文件和共享库中的符号引用,并将它们绑定到相应的符号定义。符号绑定是将符号引用与符号定义相关联的过程,确保程序能够正确地访问和执行所需的符号。通过符号绑定,dyld 确保程序能够正确链接并执行依赖的函数和变量。

3.objc(Notify ObjC Runtime)
  • mapimages 对二进制文件内容解析处理。
  • runtime在此处初始化,对class和category进行注册。
  • 进行各种objc结构的初始化(objc 类被定义和注册)。
  • 分类被插入到方法列表中。
  • selector唯一性判断。
4.Initializers
  • loadimages 调用 call_load_images 加载 类和 分类的 load方法
  • 调用c++静态初始化器和__attribute(construct)修饰的函数

至此可执行文件和动态库的符号sel  class protocol IMP 都已经按需加载到内存中了,被runtime管理最后,Dyld calls main()

三.进入main函数

  • 接下来就是 UIApplicationMain 函数,相关的调用了,Appdelegate会依次执行 对应的生命周期方法。

  • 创建整个app的autoreleasepool,初始化初始window,app界面开始展。

  • 指定rootviewcontroller,调用业务代码,完成各阶段业务。

  • main页面viewDidAppear 完成页面第一帧渲染。至此启动完成。

关于启动标准

苹果的标准

  • 针对启动时间的最佳标准 (400ms 是一个很好的目标)

  • 最坏的情况 (不要超过20秒否则应用程序将被杀死)

关于优化方案

优化方案从各个阶段来考虑

1.加载mach-o阶段

重新排列函数符号位置,降低MACH-O文件载入内存时PageFault缺页中断频率 - 二进制重排

  • 一种是抖音的方案二进制重排。(官方说会有百分之30提升,自己尝试并没有太大提升。)
  • 另外是苹果推出的pgo。(大概有百分之10左右的提升)

两者类似

原理

二进制重排实际上是在windows和linux上就存在的技术,旨在将启动用到的函数方法尽可能的放置在二进制文件加载的前面,并且是将函数符号地址连续的编译在一起,以减少Page Fault的次数和频率,加快启动速度。现在这项技术已经移植运用到了移动端app上。

操作系统为了解决安全问题和效率问题,抽象出了虚拟内存页的概念。内存都是分页访问的。这里的page指的就是内存页。(就像磁盘存储的最小单位 磁盘簇,大小是4k一样) MacOS 、linux (4K为一页) iOS(16K为一页)

PageFault就是缺页中断:当app调用一个方法,发现该方法没有在内存中,此时操作系统就会立刻阻塞整个app进程,触发一个缺页中断。操作系统会从磁盘中读取这页数据到物理内存上 , 然后再将其映射到虚拟内存上 ( 如果当前内存已满 , 操作系统会通过置换页算法 找一页数据进行覆盖, 这也是为什么开再多的应用也不会崩掉 , 但是之前开的应用再打开时 , 就重新启动了的根本原因 )。

假如,app启动时期需要调用 method1、method5和method6,这三个方法分布在page1、page2和page3上。每装载一个内存页page都会发生一次PageFault(缺页终端)。通常一个PageFault的处理时间是0.1ms~1ms,取0.5ms计算。这三次处理PageFault时间是 3 * 0.5ms = 1.5ms。

page1.webp

page1.png

2.针对dyld阶段

  • 减少动态库 合并动态库 (定期清理不必要的动态库)

  • 减少oc 类 分类 方法 sel(定期清理不必要的类 分类)

  • 减少c++虚函数数量

  • swift尽量使用struct

3.针对objc 和 initialize 可以看做是 runtime  阶段

  • 用+initialize方法和dispatch_once取代所有的__attribute__((constructor))、C++静态构造器、ObjC的+load

4. Pour l'étape après la fonction principale

  • En partant du principe de ne pas affecter l'expérience utilisateur, retardez certaines opérations autant que possible et ne les mettez pas toutes dans la méthode finishLaunching
  • Ajustement et optimisation de l'ordre des tâches de démarrage
  • Réduire la complexité de la vue initiale
  • charger à la demande

À propos des tests (nous vous recommandons de tester sur l'appareil pris en charge le plus lent)

1. Recommander 2 outils github

2. Xcode et l'instrument sont livrés avec des outils

  • Dans le paramètre de l'outil de débogage lldb Modifier le schéma -> Exécuter -> Arguments, définissez la variable d'environnement DYLD_PRINT_STATISTICS sur 1 et les résultats statistiques seront affichés dans la fenêtre d'impression

image.png

image.png

  • Lancement par instrument

3. Surveillance en ligne

Les points d'enfouissement actifs sont divisés en pré-principal et après principal

v2-d46b6f2bd967c78f704cccbb05584caa_1440w.webp

Grâce à la métrique d'Apple

image.png

Résumer

Ce qui précède couvre essentiellement le processus détaillé de chaque étape du démarrage d'iOS, ainsi que le plan d'optimisation. Bien sûr, l'optimisation du démarrage est également un indicateur de stabilité auquel il faut prêter attention pendant longtemps. Il doit également être optimisé étape par étape. étape en combinaison avec la situation actuelle du projet. Grâce à l'optimisation> surveillance> optimisation, une boucle fermée est formée pour trouver des problèmes et résoudre le problème, il y aura certainement des avantages s'il continue à la fin.

Guess you like

Origin juejin.im/post/7246777363256918073