iOS啟動優(yōu)化

希望總結(jié)項(xiàng)目中的啟動優(yōu)化,詳細(xì)學(xué)習(xí)iOS啟動流程

1. 想要對App進(jìn)行啟動優(yōu)化需要優(yōu)先了解App的啟動時(shí)間,和個(gè)個(gè)啟動過程中的時(shí)間占比(主要講解Pre-main之前的過程)

  • Xcode 13.0 beta / iOS 15.0之前比較方便我們可以在 Xcode 中配置環(huán)境變量 DYLD_PRINT_STATISTICS 為 1(Edit Scheme → Run → Arguments → Environment Variables → +)。
截屏2023-07-22 22.18.59.png
  • Xcode 13.0 beta / iOS 15.0之后這個(gè)方法失效了蘋果推薦我們使用instrument工具進(jìn)行監(jiān)測
截屏2023-07-22 22.20.51.png

2. 了解了方法后我們可以通過打印看到我們每個(gè)過程消耗的時(shí)間,此處有幾個(gè)關(guān)鍵指標(biāo)

  • dylib loading (動態(tài)庫加載)

  • rebase/binding (偏移修正/符號綁定)

rebase(偏移修正):任何一個(gè)app生成的二進(jìn)制文件,在二進(jìn)制文件內(nèi)部所有的方法、函數(shù)調(diào)用,都有一個(gè)地址蒜哀,這個(gè)地址是在當(dāng)前二進(jìn)制文件中的偏移地址。一旦在運(yùn)行時(shí)刻(即運(yùn)行到內(nèi)存中),每次系統(tǒng)都會隨機(jī)分配一個(gè)ASLR(Address Space Layout Randomization进泼,地址空間布局隨機(jī)化)地址值(是一個(gè)安全機(jī)制蔗衡,會分配一個(gè)隨機(jī)的數(shù)值,插入在二進(jìn)制文件的開頭)乳绕,例如绞惦,二進(jìn)制文件中有一個(gè) test方法,偏移值是0x0001洋措,而隨機(jī)分配的ASLR是0x1f00济蝉,如果想訪問test方法,其內(nèi)存地址(即真實(shí)地址)變?yōu)?ASLR+偏移值 = 運(yùn)行時(shí)確定的內(nèi)存地址(即0x1f00+0x0001 = 0x1f01)

  • Objc setup (Objc相關(guān)類的注冊,selector唯一性檢查)

dyld調(diào)用的objc_init方法菠发,這個(gè)是runtime的初始化方法王滤,在這個(gè)方法里面主要的操作就是加載類(對需要的class和category進(jìn)行注冊),objc_init方法通過內(nèi)部的_dyld_objc_notify_register向dyld注冊了一個(gè)通知事件,當(dāng)有新的image(程序中對應(yīng)實(shí)例可簡稱為image雷酪,如程序可執(zhí)行文件macho淑仆,F(xiàn)ramework,bundle等)加載到內(nèi)存的時(shí)候哥力,就會觸發(fā)load_images方法蔗怠,這個(gè)方法里面就是加載對應(yīng)image里面的類,并調(diào)用load方法(在下一階段initializer),如果有繼承的類吩跋,那么會先調(diào)用父類的load方法寞射,然后調(diào)用子類的,但是在load里面不能調(diào)用[super load]锌钮。最后才是調(diào)用category的load方法桥温。總之梁丘,所有的load都會被調(diào)用到(注意:子類的initialize方法會覆蓋父類侵浸,不同于load方法)

  • initializer (初始化執(zhí)行l(wèi)oad方法,創(chuàng)建靜態(tài)全局變量等)

3. 介紹幾個(gè)概念

1.Mach-O文件
Apple出品的操作系統(tǒng)的可執(zhí)行文件格式幾乎都是mach-o,iOS當(dāng)然也不例外氛谜。
mach-o可以大致的分為三部分:

  • Header 頭部掏觉,包含可以執(zhí)行的CPU架構(gòu),比如x86,arm64
  • Load commands 加載命令值漫,包含文件的組織架構(gòu)和在虛擬內(nèi)存中的布局方式
  • Data澳腹,數(shù)據(jù),包含load commands中需要的各個(gè)段(segment)的數(shù)據(jù)杨何,每一個(gè)Segment都得大小是Page的整數(shù)倍酱塔。
image.png

2.Virtual Memory
虛擬內(nèi)存是建立在物理內(nèi)存和進(jìn)程之間的中間層。在iOS上危虱,當(dāng)內(nèi)存不足的時(shí)候羊娃,會嘗試釋放那些只讀的Page,因?yàn)橹蛔x的Page在下次被訪問的時(shí)候埃跷,可以再從磁盤讀取蕊玷。如果沒有可用內(nèi)存芦瘾,會通知在后臺的App(也就是在這個(gè)時(shí)候收到了memory warning),如果在這之后仍然沒有可用內(nèi)存集畅,則會殺死在后臺的App。

  • 虛擬內(nèi)存是在物理內(nèi)存上建立的一個(gè)邏輯地址空間缅糟,它向上(應(yīng)用)提供了一個(gè)連續(xù)的邏輯地址空間挺智,向下隱藏了物理內(nèi)存的細(xì)節(jié)。
  • 虛擬內(nèi)存使得邏輯地址可以沒有實(shí)際的物理地址窗宦,也可以讓多個(gè)邏輯地址對應(yīng)到一個(gè)物理地址赦颇。
  • 虛擬內(nèi)存被劃分為一個(gè)個(gè)大小相同的Page(64位系統(tǒng)上是16KB),提高管理和讀寫的效率赴涵。 Page又分為只讀和讀寫的Page媒怯。

3.Page fault
在應(yīng)用執(zhí)行的時(shí)候,它被分配的邏輯地址空間都是可以訪問的髓窜,當(dāng)應(yīng)用訪問一個(gè)邏輯Page扇苞,而在對應(yīng)的物理內(nèi)存中并不存在的時(shí)候,這時(shí)候就發(fā)生了一次Page fault寄纵。當(dāng)Page fault發(fā)生的時(shí)候鳖敷,會中斷當(dāng)前的程序,在物理內(nèi)存中尋找一個(gè)可用的Page程拭,然后從磁盤中讀取數(shù)據(jù)到物理內(nèi)存定踱,接著繼續(xù)執(zhí)行當(dāng)前程序。

4.改善APP的啟動

-在 dylib loading的過程中恃鞋,會去裝載app使用的動態(tài)庫崖媚,而每一個(gè)動態(tài)庫有它自己的依賴關(guān)系,所以會消耗時(shí)間去查找和讀取,Apple官方建議盡量少的使用自定義的動態(tài)庫恤浪,或者考慮合并多個(gè)動態(tài)庫畅哑,其中一個(gè)建議是當(dāng)大于6個(gè)的時(shí)候,則需要考慮合并它們资锰。簡單的舉個(gè)例子比如使用cocoapods管理的多個(gè)自定義的UI組件可以合并成一個(gè)自己的UIKIT,同時(shí)也建議動態(tài)庫轉(zhuǎn)靜態(tài)庫

-減少+load的方法使用,+load方法中盡量少做耗時(shí)操作,+load中代碼延遲到 main 之后子線程處理或者首頁顯示之后敢课;改為 initialize 中執(zhí)行,針對 initialize 中處理需要注意的是分類 initialize 會覆蓋主類 initialize 以及有子類后 initialize 執(zhí)行多次的問題绷杜,需要使用 dispatch_once 來保證代碼只執(zhí)行一次;

-二進(jìn)制重排要實(shí)現(xiàn)符號的重排直秆,一是需要我們收集整個(gè)啟動鏈路上的方法和函數(shù)等符號,二是需要生成對應(yīng)的 order 文件來配置 ld 中的 Order File 屬性鞭盟。當(dāng)工程在編譯的時(shí)候圾结,Xcode 會讀取這個(gè) order 文件,在鏈接過程中會根據(jù)這個(gè)文件中的符號順序來生成對應(yīng)的 MachO齿诉。一般業(yè)界中收集符號的方案有兩種:
1.Hook objc_msgSend筝野,只能拿到 OC 以及 swift @objc dynamic 的符號晌姚;
2.Clang 插樁,能完美拿到 OC歇竟、C/C++挥唠、Swift、Block 的符號焕议;
第二種方法實(shí)現(xiàn)成本較高
采用第一種方法在編譯完成后通過驗(yàn)證 LinkMap 文件中 #Symbols: 部分符號順序是否和 order 文件中的符號順序一致來確定是否配置成功即可

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末宝磨,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子盅安,更是在濱河造成了極大的恐慌唤锉,老刑警劉巖,帶你破解...
    沈念sama閱讀 210,914評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件别瞭,死亡現(xiàn)場離奇詭異窿祥,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)蝙寨,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,935評論 2 383
  • 文/潘曉璐 我一進(jìn)店門晒衩,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人墙歪,你說我怎么就攤上這事浸遗。” “怎么了箱亿?”我有些...
    開封第一講書人閱讀 156,531評論 0 345
  • 文/不壞的土叔 我叫張陵跛锌,是天一觀的道長。 經(jīng)常有香客問我届惋,道長髓帽,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,309評論 1 282
  • 正文 為了忘掉前任脑豹,我火速辦了婚禮郑藏,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘瘩欺。我一直安慰自己必盖,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,381評論 5 384
  • 文/花漫 我一把揭開白布俱饿。 她就那樣靜靜地躺著歌粥,像睡著了一般。 火紅的嫁衣襯著肌膚如雪拍埠。 梳的紋絲不亂的頭發(fā)上失驶,一...
    開封第一講書人閱讀 49,730評論 1 289
  • 那天,我揣著相機(jī)與錄音枣购,去河邊找鬼嬉探。 笑死擦耀,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的涩堤。 我是一名探鬼主播眷蜓,決...
    沈念sama閱讀 38,882評論 3 404
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼胎围!你這毒婦竟也來了账磺?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,643評論 0 266
  • 序言:老撾萬榮一對情侶失蹤痊远,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后氏捞,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體碧聪,經(jīng)...
    沈念sama閱讀 44,095評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,448評論 2 325
  • 正文 我和宋清朗相戀三年液茎,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了逞姿。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,566評論 1 339
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡捆等,死狀恐怖滞造,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情栋烤,我是刑警寧澤谒养,帶...
    沈念sama閱讀 34,253評論 4 328
  • 正文 年R本政府宣布,位于F島的核電站明郭,受9級特大地震影響买窟,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜薯定,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,829評論 3 312
  • 文/蒙蒙 一始绍、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧话侄,春花似錦亏推、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,715評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至变丧,卻和暖如春篇亭,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背锄贷。 一陣腳步聲響...
    開封第一講書人閱讀 31,945評論 1 264
  • 我被黑心中介騙來泰國打工译蒂, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留曼月,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,248評論 2 360
  • 正文 我出身青樓柔昼,卻偏偏與公主長得像哑芹,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子捕透,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,440評論 2 348

推薦閱讀更多精彩內(nèi)容