iOS啟動原理(一)

背景

iOS的啟動過程一直比較神秘捎迫,這方面的資料也不是太多晃酒,大多數(shù)的資料都來自2016年WWDC的一篇視頻,本文的大部分內(nèi)容來自于視頻窄绒,算是視頻的一個歸納總結(jié)再加上自己的一點點感悟吧贝次。

啟動的過程

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

  1. 內(nèi)核將App的執(zhí)行文件加載到隨機地址空間(加載到隨機地址主要是因為ASLR技術(shù))
  2. 內(nèi)核將dyld的執(zhí)行文件加載到隨機地址空間
  3. 內(nèi)核執(zhí)行dyld文件
  4. dyld啟動App
    1. dyld加載所有App所依賴的dylibs(動態(tài)庫)
    2. 執(zhí)行rebasing/binding修復(fù)地址
    3. Objc Setup
    4. initialize
  5. dyld調(diào)用App中的main()蛔翅,將主動權(quán)交還給App

手機內(nèi)核只負責(zé)將App的執(zhí)行文件和dyld加載到內(nèi)存中,然后所有的啟動工作都交給了dyld位谋。

dyld加載App依賴的dylibs

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

segment

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

__TEXT: 一般處于文件的頭部位置,包含Mach header陶缺,被執(zhí)行的代碼钾挟,和只讀常量,只讀可執(zhí)行(r-x)饱岸。由于不會被更改掺出,所以讀到內(nèi)存中后可復(fù)用
__DATA: 包含各種變量,可讀寫(rw-)苫费,由于可以被更改汤锨,所以不可復(fù)用
__LINKEDIT: 包含函數(shù)名稱和對應(yīng)的地址,只讀(r--)

mmap()

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

同時同一個Mach-O文件中的segment也可以映射到多個進程,實現(xiàn)進程之間的內(nèi)存共享方椎。__TEXT__LINKEDIT段都是只讀的聂抢,不會有進程對它進行修改,它們是可以讓所有進程共享的棠众,大家都使用同一份內(nèi)容琳疏。然而__DATA段卻不是這樣,__DATA是可讀寫的闸拿,當(dāng)某一個進程需要對它進行修改時空盼,需要先copy一份出來,映射到新的 RAM 頁上新荤。讓這個進程擁有自己獨立的內(nèi)存拷貝揽趾,進行修改。這就是Copy-On-Write技術(shù)苛骨,簡稱COW篱瞎。

由于__TEXT__LINKEDIT段可以進程間共享,只需要在第一次使用的時候進行IO操作痒芝,后續(xù)即可直接使用俐筋,所以App在第一次啟動時會比較費時,因為所有的segment讀取都需要進行IO操作严衬。后續(xù)啟動澄者,會快很多,很多segment已經(jīng)映射到內(nèi)存中请琳,會被緩存起來粱挡,二次啟動直接使用,不需要進行IO操作单起,這就有了iOS中冷啟動和熱啟動的概念:

  1. 冷啟動:新安裝App或者手機重啟后抱怔,第一次啟動。手機需要加載所有的segment
  2. 熱啟動:啟動過App后嘀倒,再次啟動屈留。內(nèi)存中緩存的segment可以直接復(fù)用。

執(zhí)行rebasing/binding修復(fù)地址

由于App和每個dylib加載到的都是隨機地址空間测蘑,代碼中原來的函數(shù)地址跟真實的函數(shù)地址會有差異灌危。修復(fù)這個差異的過程就是rebasing和binding。其中rebasing主要做的是image內(nèi)部的修復(fù)碳胳,binding主要做的是image間的修復(fù)勇蝙。

Rebasing

對于Image內(nèi)部的函數(shù),假設(shè)它的原地址是A挨约,對應(yīng)當(dāng)前地址空間下的新地址是B味混。那么它所有的函數(shù)指針都需要加上地址差(B-A)产雹。所有的Rebasing過程就是從__LINKEDIT取出函數(shù)指針,修改函數(shù)指針翁锡,存入__DATA中蔓挖,供函數(shù)調(diào)用。(原始的函數(shù)指針存在__LINKEDIT中馆衔,修改后的數(shù)據(jù)存在__DATA中)

之前說到瘟判,加載文件使用的是mmap技術(shù),__LINKEDITDATA段是在第一次使用時才會執(zhí)行IO操作角溃,加載到內(nèi)存中拷获。所以Rebasing階段,耗時主要是在IO操作上减细。

Binding

image間的函數(shù)指針匆瓜,實際是被符號名稱綁定的,為了找到對應(yīng)的函數(shù)實現(xiàn)邪财,dyld需要去符號表中根據(jù)符號名稱查找陕壹,找到后將地址存到__DATA中對應(yīng)函數(shù)指針中。由于IO操作在rebasing階段已經(jīng)在做了树埠,所以binding階段主要耗時在符號表查找的這個過程糠馆,這個過程的主要瓶頸在CPU計算上。

Objc Setup

Objc是一門動態(tài)語言怎憋,為了維持它的動態(tài)性又碌,在啟動時,需要將類的名稱和類的方法都注冊起來绊袋。Objc Setup階段毕匀,主要是做Class的注冊,Method的注冊和Category的注冊癌别。

一個好的設(shè)計模式皂岔,一般都推崇寫很多類,每個類盡量簡單展姐,寫很多Category躁垛,每個Category都只包含獨立模塊的方法。但是從啟動速度的角度來說圾笨,盡量減少類教馆,Category和方法,才會讓Objc Setup階段耗時更少擂达。

initialize

當(dāng)所有的Class和method都注冊過后土铺,系統(tǒng)需要做一些初始化的工作,對于Objective-C而言,主要是需要調(diào)用各個類的+load方法悲敷,所以項目中應(yīng)該盡量避免使用+load方法究恤,正常的初始化工作,可以在initialize中實現(xiàn)后德。StackOverflow上有詳細的關(guān)于+loadinitialize的對比

End

當(dāng)上面所有階段執(zhí)行完成之后丁溅,dyld會調(diào)用main()函數(shù),將主動權(quán)交還給App探遵。之后才會調(diào)用到didFinishLaunch中的代碼。

上面介紹的啟動時間主要是main()函數(shù)之前的啟動時間妓柜,正常這個時間控制在400ms以內(nèi)就可以算一個啟動速度優(yōu)異的App了箱季。正常我們關(guān)注更多的可能是main()函數(shù)后didFinishLaunch中代碼的執(zhí)行時間。但是對用戶而言棍掐,main()函數(shù)之前的時間也是啟動的一部分藏雏。往往這部分時間也不短,所以不能掉以輕心哦~

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末作煌,一起剝皮案震驚了整個濱河市掘殴,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌粟誓,老刑警劉巖奏寨,帶你破解...
    沈念sama閱讀 206,214評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異鹰服,居然都是意外死亡病瞳,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評論 2 382
  • 文/潘曉璐 我一進店門悲酷,熙熙樓的掌柜王于貴愁眉苦臉地迎上來套菜,“玉大人,你說我怎么就攤上這事设易《翰瘢” “怎么了?”我有些...
    開封第一講書人閱讀 152,543評論 0 341
  • 文/不壞的土叔 我叫張陵顿肺,是天一觀的道長戏溺。 經(jīng)常有香客問我,道長挟冠,這世上最難降的妖魔是什么于购? 我笑而不...
    開封第一講書人閱讀 55,221評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮知染,結(jié)果婚禮上肋僧,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好嫌吠,可當(dāng)我...
    茶點故事閱讀 64,224評論 5 371
  • 文/花漫 我一把揭開白布止潘。 她就那樣靜靜地躺著,像睡著了一般辫诅。 火紅的嫁衣襯著肌膚如雪凭戴。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,007評論 1 284
  • 那天炕矮,我揣著相機與錄音么夫,去河邊找鬼。 笑死肤视,一個胖子當(dāng)著我的面吹牛档痪,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播邢滑,決...
    沈念sama閱讀 38,313評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼腐螟,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了困后?” 一聲冷哼從身側(cè)響起乐纸,我...
    開封第一講書人閱讀 36,956評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎摇予,沒想到半個月后汽绢,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,441評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡趾盐,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,925評論 2 323
  • 正文 我和宋清朗相戀三年庶喜,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片救鲤。...
    茶點故事閱讀 38,018評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡久窟,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出本缠,到底是詐尸還是另有隱情斥扛,我是刑警寧澤,帶...
    沈念sama閱讀 33,685評論 4 322
  • 正文 年R本政府宣布丹锹,位于F島的核電站稀颁,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏楣黍。R本人自食惡果不足惜匾灶,卻給世界環(huán)境...
    茶點故事閱讀 39,234評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望租漂。 院中可真熱鬧阶女,春花似錦颊糜、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,240評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至憔杨,卻和暖如春鸟赫,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背消别。 一陣腳步聲響...
    開封第一講書人閱讀 31,464評論 1 261
  • 我被黑心中介騙來泰國打工抛蚤, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人寻狂。 一個月前我還...
    沈念sama閱讀 45,467評論 2 352
  • 正文 我出身青樓霉颠,卻偏偏與公主長得像,于是被迫代替她去往敵國和親荆虱。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,762評論 2 345

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

  • 這是一篇 WWDC 2016 Session 406 的學(xué)習(xí)筆記朽们,從原理到實踐講述了如何優(yōu)化 App 的啟動時間怀读。...
    請叫我周小帥閱讀 513評論 0 2
  • App 運行理論 理論速成Mach-O 術(shù)語Mach-O 是針對不同運行時可執(zhí)行文件的文件類型。文件類型:Exec...
    未明一二閱讀 542評論 1 3
  • 這是一篇 WWDC 2016 Session 406 的學(xué)習(xí)筆記骑脱,從原理到實踐講述了如何優(yōu)化 App 的啟動時間菜枷。...
    MTDeveloper閱讀 746評論 0 1
  • 這是一篇 WWDC 2016 Session 406 的學(xué)習(xí)筆記,從原理到實踐講述了如何優(yōu)化 App 的啟動時間叁丧。...
    茗涙閱讀 1,858評論 0 3
  • 別說臺北啤誊,就連臺灣,很多細節(jié)我都記不太清楚了拥娄。 已經(jīng)過去了三年蚊锹,怎么買票,怎么坐車稚瘾,怎么住宿牡昆,去哪兒玩,吃啥摊欠,多少...
    吹手閱讀 791評論 6 3