WWDC關(guān)于APP啟動的建議

一些概念

Mach-O是運(yùn)行時產(chǎn)生的可執(zhí)行文件的文件類型
  • Image:

    • Executable:程序的主二進(jìn)制文件
    • Dylib:動態(tài)庫
    • Bundle:是一種特殊的Dylib赦役,是不能進(jìn)行鏈接的,只能在運(yùn)行時用dlopen()函數(shù)打開。
  • Framework:Dylib+儲存該Dylib需要的資源候址、頭文件的目錄結(jié)構(gòu)

Mach-O Image File被分割成幾個段
引用自WWDC2016
  • _TEXT:頭文件,代碼,只讀常量
  • _DATA:所有可讀寫內(nèi)容(全局變量、靜態(tài)變量等等)
  • _LINKEDIT:儲存關(guān)于如何加載程序的“元數(shù)據(jù)”

每個段都是page size的倍數(shù)痪蝇,圖中_TEXT占有三個page,arm64一個page size是16KB冕房,其它的是4KB


虛擬內(nèi)存把每一個進(jìn)程地址映射到物理內(nèi)存RAM中:
  • page錯誤
  • 多個進(jìn)程中出現(xiàn)的相同的RAM page
  • 文件回溯page:mmap()躏啰、延遲讀取(lazy reading)
  • Copy-On-Write(COW)
  • 臟page和干凈page
  • Permissions:rwx


安全:

ASLR(Address space layout randomization)是一種針對緩沖區(qū)溢出的安全保護(hù)技術(shù),通過對堆毒费、棧丙唧、共享庫映射等線性區(qū)布局的隨機(jī)化,通過增加攻擊者預(yù)測目的地址的難度觅玻,防止攻擊者直接定位攻擊代碼位置,達(dá)到阻止溢出攻擊的目的培漏。據(jù)研究表明ASLR可以有效的降低緩沖區(qū)溢出攻擊的成功率溪厘,如今Linux、FreeBSD牌柄、Windows等主流操作系統(tǒng)都已采用了該技術(shù)畸悬。

ASLR:
  • 地址空間隨機(jī)布局
  • 鏡像(Images)加載在隨機(jī)的地址

代碼簽名

  • 每一個page擁有的內(nèi)容
  • page內(nèi)的哈希驗證

exec()到main(),內(nèi)核讓你的App在隨機(jī)的地址開始運(yùn)行


什么是Dyld珊佣?
  • Dyld是動態(tài)加載器蹋宦,內(nèi)核加載的輔助程序
  • 程序從Dyld開始執(zhí)行
  • Dyld運(yùn)行在進(jìn)程中
  • Dyld負(fù)責(zé)加載動態(tài)依賴庫
  • Dyld擁有與App相同的權(quán)限



Main()函數(shù)之前的五個階段

Dyld主導(dǎo)的五個階段:
引用自WWDC2016
一披粟、Load dylibs:

動態(tài)映射所有的動態(tài)依賴庫。

  1. 解析動態(tài)依賴庫(dylib)的列表
  2. 找到所有需要的mach-o(dylib)文件
  3. 打開并讀取每一個找到的文件
  4. 驗證這些文件是不是mach-o文件
  5. 找到它的編碼簽名冷冗,在內(nèi)核里對它進(jìn)行注冊
  6. 給每一個分段調(diào)用映射

現(xiàn)在守屉,所有App指向的動態(tài)依賴庫都被遞歸加載,App通常需要加載100-400個動態(tài)庫蒿辙,大多數(shù)是OS(操作系統(tǒng))的動態(tài)庫

二拇泛、Rebase

遍歷所有內(nèi)部數(shù)據(jù)指針為他們添加一個滑動值。這些指針的位置都被編碼在__LINKEDIT段里思灌。

  1. 調(diào)整所有鏡像內(nèi)的指針俺叭,添加一個slide偏差值。
Slide = actual_address - preferred_address
  1. 出于安全考慮泰偿,引入了 ASLR熄守,全稱 Address Space Layout Randomization

大概意思就是鏡像(dylib)會加載在隨機(jī)的地址上耗跛,和actual_address會有一個偏差(slide)裕照,dyld需要修正這個偏差,來指向正確的地址课兄。

  1. Rebase+Bind+ObjC大多數(shù)時間在做修復(fù):
    • 代碼簽名意味著命令不能被修改
    • 代碼不能被加載到任何地址上牍氛,而且永遠(yuǎn)不能被修改
    • 所有的修復(fù)都發(fā)生在__DATA數(shù)據(jù)段
三、Bind

遍歷查詢符號表烟阐,設(shè)置指向鏡像外部的指針搬俊。

  1. 所有在其它動態(tài)庫引用的東西都會符號化
  2. Dyld需要找到所有符號名
  3. 會比Rebasing進(jìn)行更多的計算
四、ObjC

通知 runtime 準(zhǔn)備鏡像蜒茄、OC類的注冊唉擂、偏移ivar的地址、加載Category

  1. runtime要維護(hù)一張表檀葛,包含所有類名(Class Name)及其映射的類(Class)
  2. 完成所有OC類的定義注冊
  3. 運(yùn)行時改變所有ivar的偏移量
  4. 接下來在ObjC階段可以定義分類(Category)
  5. 最后讓Selector都是唯一的
五玩祟、Initializers
  1. dyld開始調(diào)用C++靜態(tài)構(gòu)造函數(shù),初始化器用來初始化那些抽象DATA

  2. 調(diào)用所有類的 +load 方法,順序:父類->子類->Category

  3. 每個Initializers按照從下向上的順序執(zhí)行屿聋。

    為什么從下向上空扎?

    因為當(dāng)Initializers運(yùn)行時,可能會調(diào)用一些dylib润讥,我們需要確保那些dylib已經(jīng)準(zhǔn)備好被調(diào)用转锈,所以從下開始運(yùn)行Initializers,一直往上到應(yīng)用類楚殿,可以很安全的調(diào)用依賴的內(nèi)容撮慨。

  4. 最后Dyld調(diào)用main()函數(shù)

小結(jié):Dyld是一個輔助程序
  1. 加載所有的依賴庫
  2. 修復(fù)所有DATA page中的指針
  3. 運(yùn)行所有的初始化器(Initializers)
  4. 跳轉(zhuǎn)到主函數(shù)

優(yōu)化啟動時間的實踐部分

  • 啟動時間如果在400ms(0.4s)以內(nèi)會讓用戶覺得啟動快
  • 啟動時間千萬不要超過20s,否則OS將會認(rèn)為你的APP進(jìn)入死循環(huán),殺死APP
App啟動都做了什么砌溺?

在main函數(shù)之前的五個階段之后影涉,還要調(diào)用:

  1. main()

  2. UIApplicationMain() : 加載framework的初始化器,加載nibs

  3. applicationWillFinishLaunching

以上8個步驟都算在這400ms內(nèi)规伐。


熱啟動和冷啟動
  • 熱啟動:App及其數(shù)據(jù)已經(jīng)在內(nèi)存(磁盤)中
  • 冷啟動:App不在內(nèi)核的緩存中


優(yōu)化方案:

一蟹倾、Load Dylib階段
  1. 合并已有的動態(tài)庫(包括framework),限制動態(tài)庫(包括framework)個數(shù)效果非常明顯
  2. 使用靜態(tài)庫代替

  3. 可以使用延遲加載楷力,也就是使用dlopen()函數(shù)喊式,但是dlopen()會帶來細(xì)微的性能和正確性的問題。


    優(yōu)化前的鏈接庫個數(shù)

    優(yōu)化前的啟動時間

原有26個framework合并成2個后萧朝,由240ms變?yōu)?1ms岔留。

優(yōu)化后的鏈接庫個數(shù)

優(yōu)化后的啟動時間
二、Rebase和Bind階段
  1. 減少OC元數(shù)據(jù)
    • 減少OC類的數(shù)量(不鼓勵使用很多很小的類检柬,只有一兩個方法的那種)
    • 減少selector的數(shù)量
    • 減少Category的數(shù)量
  2. 減少C++虛擬函數(shù)献联,虛擬函數(shù)創(chuàng)建被稱作 V表格,和OC元數(shù)據(jù)相同

  3. 避免讓機(jī)器生成過多的代碼何址,機(jī)器生成的指針非常耗內(nèi)存
    • 使用偏移量代替指針
    • 標(biāo)記為只讀
三里逆、ObjC階段

這個階段的優(yōu)化工作已經(jīng)在Rebase和Bind階段做完了

四、Initializers階段

有兩種Initializers:顯式和隱式

顯式:
  1. +load
方案:使用 +initiailize 代替


  1. C/C++的 __attribute__((constructor))

方案:使用site initializers

  • 使用dispatch_once()
  • 使用pthread_once()
  • 使用std::once()

隱式:大部分是C++的全局變量帶來的非默認(rèn)初始化器
  1. 使用site initializers
  2. 只設(shè)置簡單的值
  3. 不要在初始化器中調(diào)用dlopen()
  4. 不要在初始化器中創(chuàng)建線程


參考

WWDC2016-406

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末用爪,一起剝皮案震驚了整個濱河市原押,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌偎血,老刑警劉巖诸衔,帶你破解...
    沈念sama閱讀 219,589評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異颇玷,居然都是意外死亡笨农,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,615評論 3 396
  • 文/潘曉璐 我一進(jìn)店門帖渠,熙熙樓的掌柜王于貴愁眉苦臉地迎上來谒亦,“玉大人,你說我怎么就攤上這事空郊》菡校” “怎么了?”我有些...
    開封第一講書人閱讀 165,933評論 0 356
  • 文/不壞的土叔 我叫張陵狞甚,是天一觀的道長脾还。 經(jīng)常有香客問我,道長入愧,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,976評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮棺蛛,結(jié)果婚禮上怔蚌,老公的妹妹穿的比我還像新娘。我一直安慰自己旁赊,他們只是感情好桦踊,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,999評論 6 393
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著终畅,像睡著了一般籍胯。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上离福,一...
    開封第一講書人閱讀 51,775評論 1 307
  • 那天杖狼,我揣著相機(jī)與錄音,去河邊找鬼妖爷。 笑死蝶涩,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的絮识。 我是一名探鬼主播绿聘,決...
    沈念sama閱讀 40,474評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼次舌!你這毒婦竟也來了熄攘?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,359評論 0 276
  • 序言:老撾萬榮一對情侶失蹤彼念,失蹤者是張志新(化名)和其女友劉穎挪圾,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體国拇,經(jīng)...
    沈念sama閱讀 45,854評論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡洛史,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,007評論 3 338
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了酱吝。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片也殖。...
    茶點(diǎn)故事閱讀 40,146評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖务热,靈堂內(nèi)的尸體忽然破棺而出忆嗜,到底是詐尸還是另有隱情,我是刑警寧澤崎岂,帶...
    沈念sama閱讀 35,826評論 5 346
  • 正文 年R本政府宣布捆毫,位于F島的核電站,受9級特大地震影響冲甘,放射性物質(zhì)發(fā)生泄漏绩卤。R本人自食惡果不足惜途样,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,484評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望濒憋。 院中可真熱鬧何暇,春花似錦、人聲如沸凛驮。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,029評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽黔夭。三九已至宏胯,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間本姥,已是汗流浹背肩袍。 一陣腳步聲響...
    開封第一講書人閱讀 33,153評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留扣草,地道東北人了牛。 一個月前我還...
    沈念sama閱讀 48,420評論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像辰妙,于是被迫代替她去往敵國和親鹰祸。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,107評論 2 356