iOS啟動原理(一)

背景

iOS的啟動過程一直比較神秘,這方面的資料也不是太多,大多數的資料都來自2016年WWDC的一篇視頻,本文的大部分內容來自于視頻,算是視頻的一個歸納總結再加上自己的一點點感悟吧。

啟動的過程

dyld是App的啟動器,啟動的大部分事情都由dyld完成,iOS的啟動大致分為幾個部分:

  1. 內核將App的執行文件加載到隨機地址空間(加載到隨機地址主要是因為ASLR技術)
  2. 內核將dyld的執行文件加載到隨機地址空間
  3. 內核執行dyld文件
  4. dyld啟動App
    1. dyld加載所有App所依賴的dylibs(動態庫)
    2. 執行rebasing/binding修復地址
    3. Objc Setup
    4. initialize
  5. dyld調用App中的main(),將主動權交還給App

手機內核只負責將App的執行文件和dyld加載到內存中,然后所有的啟動工作都交給了dyld。

dyld加載App依賴的dylibs

dyld拿到App的執行文件后,首先從文件的header中解析出App依賴的dylib列表,找到每一個依賴的dylib。打開并讀取dylib文件的起始位置,驗證簽名,確保dylib沒有被篡改。驗證簽名后,對dylib中的每個segment調用mmap()

segment

一般每個Mach-O文件都會有三個segment:

__TEXT: 一般處于文件的頭部位置,包含Mach header,被執行的代碼,和只讀常量,只讀可執行(r-x)。由于不會被更改,所以讀到內存中后可復用
__DATA: 包含各種變量,可讀寫(rw-),由于可以被更改,所以不可復用
__LINKEDIT: 包含函數名稱和對應的地址,只讀(r--)

mmap()

文件讀入內存并不用一次性讀入整個文件,它可以使用分頁映射(mmap())的方式進行讀取。也就是用到哪個segment,再將哪個segment讀入內存,實現文件讀入的懶加載。

同時同一個Mach-O文件中的segment也可以映射到多個進程,實現進程之間的內存共享。__TEXT__LINKEDIT段都是只讀的,不會有進程對它進行修改,它們是可以讓所有進程共享的,大家都使用同一份內容。然而__DATA段卻不是這樣,__DATA是可讀寫的,當某一個進程需要對它進行修改時,需要先copy一份出來,映射到新的 RAM 頁上。讓這個進程擁有自己獨立的內存拷貝,進行修改。這就是Copy-On-Write技術,簡稱COW。

由于__TEXT__LINKEDIT段可以進程間共享,只需要在第一次使用的時候進行IO操作,后續即可直接使用,所以App在第一次啟動時會比較費時,因為所有的segment讀取都需要進行IO操作。后續啟動,會快很多,很多segment已經映射到內存中,會被緩存起來,二次啟動直接使用,不需要進行IO操作,這就有了iOS中冷啟動和熱啟動的概念:

  1. 冷啟動:新安裝App或者手機重啟后,第一次啟動。手機需要加載所有的segment
  2. 熱啟動:啟動過App后,再次啟動。內存中緩存的segment可以直接復用。

執行rebasing/binding修復地址

由于App和每個dylib加載到的都是隨機地址空間,代碼中原來的函數地址跟真實的函數地址會有差異。修復這個差異的過程就是rebasing和binding。其中rebasing主要做的是image內部的修復,binding主要做的是image間的修復。

Rebasing

對于Image內部的函數,假設它的原地址是A,對應當前地址空間下的新地址是B。那么它所有的函數指針都需要加上地址差(B-A)。所有的Rebasing過程就是從__LINKEDIT取出函數指針,修改函數指針,存入__DATA中,供函數調用。(原始的函數指針存在__LINKEDIT中,修改后的數據存在__DATA中)

之前說到,加載文件使用的是mmap技術,__LINKEDITDATA段是在第一次使用時才會執行IO操作,加載到內存中。所以Rebasing階段,耗時主要是在IO操作上。

Binding

image間的函數指針,實際是被符號名稱綁定的,為了找到對應的函數實現,dyld需要去符號表中根據符號名稱查找,找到后將地址存到__DATA中對應函數指針中。由于IO操作在rebasing階段已經在做了,所以binding階段主要耗時在符號表查找的這個過程,這個過程的主要瓶頸在CPU計算上。

Objc Setup

Objc是一門動態語言,為了維持它的動態性,在啟動時,需要將類的名稱和類的方法都注冊起來。Objc Setup階段,主要是做Class的注冊,Method的注冊和Category的注冊。

一個好的設計模式,一般都推崇寫很多類,每個類盡量簡單,寫很多Category,每個Category都只包含獨立模塊的方法。但是從啟動速度的角度來說,盡量減少類,Category和方法,才會讓Objc Setup階段耗時更少。

initialize

當所有的Class和method都注冊過后,系統需要做一些初始化的工作,對于Objective-C而言,主要是需要調用各個類的+load方法,所以項目中應該盡量避免使用+load方法,正常的初始化工作,可以在initialize中實現。StackOverflow上有詳細的關于+loadinitialize的對比

End

當上面所有階段執行完成之后,dyld會調用main()函數,將主動權交還給App。之后才會調用到didFinishLaunch中的代碼。

上面介紹的啟動時間主要是main()函數之前的啟動時間,正常這個時間控制在400ms以內就可以算一個啟動速度優異的App了。正常我們關注更多的可能是main()函數后didFinishLaunch中代碼的執行時間。但是對用戶而言,main()函數之前的時間也是啟動的一部分。往往這部分時間也不短,所以不能掉以輕心哦~

?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,702評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,143評論 3 415
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,553評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,620評論 1 307
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,416評論 6 405
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 54,940評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,024評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,170評論 0 287
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,709評論 1 333
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,597評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,784評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,291評論 5 357
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,029評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,407評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,663評論 1 280
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,403評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,746評論 2 370

推薦閱讀更多精彩內容

  • 這是一篇 WWDC 2016 Session 406 的學習筆記,從原理到實踐講述了如何優化 App 的啟動時間。...
    請叫我周小帥閱讀 524評論 0 2
  • App 運行理論 理論速成Mach-O 術語Mach-O 是針對不同運行時可執行文件的文件類型。文件類型:Exec...
    未明一二閱讀 555評論 1 3
  • 這是一篇 WWDC 2016 Session 406 的學習筆記,從原理到實踐講述了如何優化 App 的啟動時間。...
    MTDeveloper閱讀 751評論 0 1
  • 這是一篇 WWDC 2016 Session 406 的學習筆記,從原理到實踐講述了如何優化 App 的啟動時間。...
    茗涙閱讀 1,874評論 0 3
  • 別說臺北,就連臺灣,很多細節我都記不太清楚了。 已經過去了三年,怎么買票,怎么坐車,怎么住宿,去哪兒玩,吃啥,多少...
    吹手閱讀 814評論 6 3