iOS開發(fā)啟動(dòng)優(yōu)化

優(yōu)化(首頁加載時(shí)間)

  1. 整理啟動(dòng)項(xiàng), 總結(jié)出耗時(shí)長(zhǎng)的模塊
  2. 分為2部分 main函數(shù)之前耗時(shí)和mian之后耗時(shí)
  3. Main前面主要做一些動(dòng)態(tài)庫dyld的加載和load方法的調(diào)用, 對(duì)于pre-main階段赛糟,Apple提供了一種測(cè)量方法來計(jì)算耗時(shí)時(shí)長(zhǎng)
  4. 減少依賴不必要的庫白粉,無論是動(dòng)態(tài)還是靜態(tài)庫吐根,如果可以的話把動(dòng)態(tài)庫改為靜態(tài)庫
  5. 用linkmap檢測(cè)出所有的方法和類邑雅,在用AppCode找出無用代碼和類皿伺,刪除掉寝贡,減少load方法調(diào)用
  6. 少在類的+load方法里做事情悼吱,盡量把這些事情推遲到+initiailize (可以減少main之前的運(yùn)行時(shí)間)
  7. 對(duì)于main()階段沸停,主要是測(cè)量main()函數(shù)開始執(zhí)行到didFinishLaunchingWithOptions執(zhí)行結(jié)束的耗時(shí),就需要自己插入代碼到工程中了疾宏。先在main()函數(shù)里用變量StartTime記錄當(dāng)前時(shí)間, 最后在didFinishLaunchingWithOptions里张足,再獲取一下當(dāng)前時(shí)間,與StartTime的差值即是main()階段運(yùn)行耗時(shí)坎藐。
  8. 懶加載(避免在首頁控制器的viewDidLoad和viewWillAppear做太多事情为牍,這2個(gè)方法執(zhí)行完,首頁控制器才能顯示)
  9. 圖片壓縮顺饮,圖片小了吵聪,io操作量也會(huì)變小,啟動(dòng)就快了
  10. 非必要加載業(yè)務(wù)延遲去做(比如放到首頁控制器的viewDidAppear方法)
  11. 主頁不用storyboard或者xib加載, 全部改為純代碼
  12. 采用性能更好的API

應(yīng)用啟動(dòng)原理流程

  1. 點(diǎn)擊圖標(biāo)兼雄,創(chuàng)建進(jìn)程
  2. mmap 主二進(jìn)制吟逝,找到 dyld 的路徑 (mmap 的全稱是 memory map,是一種內(nèi)存映射技術(shù)赦肋,可以把文件映射到虛擬內(nèi)存的地址空間里块攒,這樣就可以像直接操作內(nèi)存那樣來讀寫文件。)
  3. mmap dyld佃乘,把入口地址設(shè)為_dyld_start (dyld 是啟動(dòng)的輔助程序囱井,是 in-process 的,即啟動(dòng)的時(shí)候會(huì)把 dyld 加載到進(jìn)程的地址空間里趣避,然后把后續(xù)的啟動(dòng)過程交給 dyld;iOS 13 開始 Apple 對(duì)三方 App 啟用了 dyld3庞呕,dyld3 的最重要的特性就是啟動(dòng)閉包,閉包里包含了啟動(dòng)所需要的緩存信息程帕,從而提高啟動(dòng)速度住练。)
  4. 重啟手機(jī)/更新/下載 App 的第一次啟動(dòng),會(huì)創(chuàng)建啟動(dòng)閉包
  5. 把沒有加載的動(dòng)態(tài)庫 mmap 進(jìn)來愁拭,動(dòng)態(tài)庫的數(shù)量會(huì)影響這個(gè)階段
  6. 對(duì)每個(gè)二進(jìn)制做 bind 和 rebase(Rebase:修復(fù)內(nèi)部指針讲逛。這是因?yàn)?Mach-O 在 mmap 到虛擬內(nèi)存的時(shí)候,起始地址會(huì)有一個(gè)隨機(jī)的偏移量 slide岭埠,需要把內(nèi)部的指針指向加上這個(gè) slide盏混。Bind:修復(fù)外部指針。這個(gè)比較好理解惜论,因?yàn)橄?printf 等外部函數(shù)许赃,只有運(yùn)行時(shí)才知道它的地址是什么,bind 就是把指針指向這個(gè)地址)来涨,主要耗時(shí)在 Page In图焰,影響 Page In 數(shù)量的是 objc 的元數(shù)據(jù)有定義,過程:MMU 找到空閑的物理內(nèi)存頁面 蹦掐;觸發(fā)磁盤 IO技羔,把數(shù)據(jù)讀入物理內(nèi)存僵闯;如果是 TEXT 段的頁,要進(jìn)行解密藤滥;對(duì)解密后的頁鳖粟,進(jìn)行簽名驗(yàn)證)
  7. 初始化 objc 的 runtime,由于閉包已經(jīng)初始化了大部分拙绊,這里只會(huì)注冊(cè) sel 和裝載 category
  8. +load 和靜態(tài)初始化被調(diào)用向图,除了方法本身耗時(shí),這里還會(huì)引起大量 Page In
  9. 初始化 UIApplication标沪,啟動(dòng) Main Runloop
  10. 執(zhí)行 will/didFinishLaunch榄攀,這里主要是業(yè)務(wù)代碼耗時(shí)
  11. Layout,viewDidLoad 和Layoutsubviews 會(huì)在這里調(diào)用金句,Autolayout 太多會(huì)影響這部分時(shí)間
  12. Display檩赢,drawRect 會(huì)調(diào)用
  13. Prepare,圖片解碼發(fā)生在這一步
  14. Commit违寞,首幀渲染數(shù)據(jù)打包發(fā)給 RenderServer贞瞒,啟動(dòng)結(jié)束


基于啟動(dòng)原理優(yōu)化

t(App 總啟動(dòng)時(shí)間) = t1(main 調(diào)用之前的加載時(shí)間) + t2(main 調(diào)用之后的加載時(shí)間),分main函數(shù)之前和main函數(shù)之后的相關(guān)方法優(yōu)化


查看耗時(shí)情況

獲得 main() 方法執(zhí)行前的耗時(shí)比較簡(jiǎn)單趁曼,通過 Xcode 自帶的測(cè)量方法既可以军浆。將 Xcode 中 Product -> Scheme -> Edit scheme -> Run -> Environment Variables 將環(huán)境變量 DYLD_PRINT_STATISTICS 或 DYLD_PRINT_STATISTICS_DETAILS 設(shè)為 1 即可獲得執(zhí)行每項(xiàng)耗時(shí):

Total pre-main time: 1.2 seconds (100.0%)

dylib loading time: 147.51 milliseconds (12.0%)

rebase/binding time: 112.82 milliseconds (9.2%)

ObjC setup time:  45.94 milliseconds (3.7%)

initializer time: 919.07 milliseconds (75.0%)

       slowest intializers :

libSystem.B.dylib :   6.79 milliseconds (0.5%)

libMainThreadChecker.dylib :  34.62 milliseconds (2.8%)

libglInterpose.dylib : 353.67 milliseconds (28.8%)

TCLTV : 944.10 milliseconds (77.0%)

優(yōu)化實(shí)踐

啟動(dòng)任務(wù)拆分優(yōu)化
(1) 確定在展示 UI 前必須執(zhí)行的任務(wù)。
如果應(yīng)用是第一次啟動(dòng)挡闰,那么沒有必要加載任何用戶偏好乒融,如主題、刷新間隔摄悯、緩存大小等簇抵。此時(shí)是沒有任何自定義值的。初始緩存肆意增長(zhǎng)也是沒問題的射众,因?yàn)樗脑鲩L(zhǎng)不會(huì)超過最終的限制值。崩潰報(bào)告系統(tǒng)應(yīng)第一個(gè)被初始化晃财。
(2) 按順序執(zhí)行任務(wù)叨橱。
排序是非常重要的,因?yàn)槿蝿?wù)之間可能具有相互依賴性断盛,同時(shí)罗洗,排序還可以節(jié)省用戶的寶貴時(shí)間。例如钢猛,如果先觸發(fā)了訪問令牌的驗(yàn)證操作伙菜,那么其他任務(wù)可能會(huì)并行執(zhí)行,因?yàn)轵?yàn)證過程需要進(jìn)行網(wǎng)絡(luò)連接命迈。但是這樣就會(huì)導(dǎo)致一種情況:如果其他任務(wù)先完成贩绕,而驗(yàn)證還未完成火的,應(yīng)用就必須等待驗(yàn)證完成才能繼續(xù)執(zhí)行。
(3) 將任務(wù)拆分為兩類:一類是必須在主線程中執(zhí)行的任務(wù)淑倾,另一類是可以在其他線程中執(zhí)行的任務(wù) 馏鹤,然后分別執(zhí)行。還可以進(jìn)一步將在非主線程中執(zhí)行的任務(wù)分為可以并發(fā)執(zhí)行的和不能并發(fā)執(zhí)行的娇哆。
(4) 其他任務(wù)可以在加載 UI 后執(zhí)行或異步執(zhí)行湃累。
延遲其他子系統(tǒng)(如記錄儀和分析方法)的初始化。在應(yīng)用的后續(xù)階段將一些操作(例如碍讨,寫日志消息或跟蹤事件)放入隊(duì)列中治力,直到子系統(tǒng)完全完成初始化。

優(yōu)化方法

(1)在t1階段加快App啟動(dòng):

  • 盡量使用靜態(tài)庫勃黍,減少動(dòng)態(tài)庫的使用宵统,動(dòng)態(tài)鏈接比較耗時(shí),如果要用動(dòng)態(tài)庫溉躲,盡量將多個(gè)dylib動(dòng)態(tài)庫合并成一個(gè)
  • 盡量避免對(duì)系統(tǒng)庫使用optional linking榜田,如果App用到的系統(tǒng)庫在你所有支持的系統(tǒng)版本上都有,就設(shè)置為required锻梳,因?yàn)閛ptional會(huì)有些額外的檢查
  • 減少Objective-C Class箭券、Selector、Category的數(shù)量疑枯,可以合并或者刪減一些OC類(怎樣刪減無用代碼:ViewConteroller 滲透率辩块,hook 對(duì)應(yīng)的聲明周期方法即可統(tǒng)計(jì);Class 滲透率荆永,遍歷運(yùn)行時(shí)的所有類废亭,通過 Objective C Runtime 的標(biāo)志位判斷類是否被訪問;行級(jí)滲透率具钥,需要用編譯期插樁豆村,對(duì)包大小和執(zhí)行速度均有損。)
  • 刪減一些無用的靜態(tài)變量骂删,刪減沒有被調(diào)用到或者已經(jīng)廢棄的方法
  • 將不必須在+load中做的事情盡量挪到+initialize中掌动,+initialize是在第一次初始化這個(gè)類之前被調(diào)用,+load在加載類的時(shí)候就被調(diào)用宁玫;或者做load方法遷移
  • 盡量不要用C++虛函數(shù)粗恢,創(chuàng)建虛函數(shù)表有開銷
  • 不要使用attribute((constructor))將方法顯式標(biāo)記為初始化器,而是讓初始化方法調(diào)用時(shí)才執(zhí)行欧瘪。比如使用dispatch_once()眷射,pthread_once()或 std::once()
  • 在初始化方法中不調(diào)用dlopen(),dlopen()有性能和死鎖的可能性
  • 在初始化方法中不創(chuàng)建線程

(2)在t2階段加快App啟動(dòng):

  • 盡量不要使用xib/storyboard,而是用純代碼作為首頁UI妖碉,如果要用xib/storyboard涌庭,不要在xib/storyboard中存放太多的視圖
  • 使用簡(jiǎn)單的廣告頁作為過渡,將首頁的計(jì)算操作及網(wǎng)絡(luò)請(qǐng)求放在廣告頁展示時(shí)異步進(jìn)行嗅绸。
  • 對(duì)application:didFinishLaunchingWithOptions:里的任務(wù)盡量延遲加載或懶加載
  • 不要在NSUserDefaults中存放太多的數(shù)據(jù)脾猛,NSUserDefaults是一個(gè)plist文件,plist文件會(huì)被反序列化一次
  • 避免在啟動(dòng)時(shí)打印過多的log鱼鸠,少用NSLog猛拴,因?yàn)槊恳淮蜰SLog的調(diào)用都會(huì)創(chuàng)建一個(gè)新的NSCalendar實(shí)例
  • 為了防止使用GCD創(chuàng)建過多的線程,解決方法是創(chuàng)建串行隊(duì)列蚀狰,或者使用帶有最大并發(fā)數(shù)限制的NSOperationQueue
  • 不要在主線程執(zhí)行磁盤愉昆、網(wǎng)絡(luò)、Lock或者dispatch_sync麻蹋、發(fā)送消息給其他線程等操作

總結(jié)

總結(jié)起來跛溉,啟動(dòng)速度優(yōu)化就一句話:讓系統(tǒng)在啟動(dòng)期間少做一些事。當(dāng)然我們得先清楚工程里做的哪些事是在啟動(dòng)期間做的扮授、對(duì)啟動(dòng)速度的影響有多大芳室,然后case by case地分析工程代碼,通過放到子線程刹勃、延遲加載堪侯、懶加載等方式讓系統(tǒng)在啟動(dòng)期間更輕松些。

iOS 啟動(dòng)優(yōu)化總結(jié)

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末荔仁,一起剝皮案震驚了整個(gè)濱河市伍宦,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌乏梁,老刑警劉巖次洼,帶你破解...
    沈念sama閱讀 216,496評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異遇骑,居然都是意外死亡卖毁,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,407評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門落萎,熙熙樓的掌柜王于貴愁眉苦臉地迎上來势篡,“玉大人,你說我怎么就攤上這事模暗。” “怎么了念祭?”我有些...
    開封第一講書人閱讀 162,632評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵兑宇,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我粱坤,道長(zhǎng)隶糕,這世上最難降的妖魔是什么瓷产? 我笑而不...
    開封第一講書人閱讀 58,180評(píng)論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮枚驻,結(jié)果婚禮上濒旦,老公的妹妹穿的比我還像新娘。我一直安慰自己再登,他們只是感情好尔邓,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,198評(píng)論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著锉矢,像睡著了一般梯嗽。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上沽损,一...
    開封第一講書人閱讀 51,165評(píng)論 1 299
  • 那天灯节,我揣著相機(jī)與錄音,去河邊找鬼绵估。 笑死炎疆,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的国裳。 我是一名探鬼主播形入,決...
    沈念sama閱讀 40,052評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼躏救!你這毒婦竟也來了唯笙?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,910評(píng)論 0 274
  • 序言:老撾萬榮一對(duì)情侶失蹤盒使,失蹤者是張志新(化名)和其女友劉穎崩掘,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體少办,經(jīng)...
    沈念sama閱讀 45,324評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡苞慢,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,542評(píng)論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了英妓。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片挽放。...
    茶點(diǎn)故事閱讀 39,711評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖蔓纠,靈堂內(nèi)的尸體忽然破棺而出辑畦,到底是詐尸還是另有隱情,我是刑警寧澤腿倚,帶...
    沈念sama閱讀 35,424評(píng)論 5 343
  • 正文 年R本政府宣布纯出,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏暂筝。R本人自食惡果不足惜箩言,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,017評(píng)論 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望焕襟。 院中可真熱鬧陨收,春花似錦、人聲如沸鸵赖。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,668評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽卫漫。三九已至菲饼,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間列赎,已是汗流浹背宏悦。 一陣腳步聲響...
    開封第一講書人閱讀 32,823評(píng)論 1 269
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留包吝,地道東北人饼煞。 一個(gè)月前我還...
    沈念sama閱讀 47,722評(píng)論 2 368
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像诗越,于是被迫代替她去往敵國(guó)和親砖瞧。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,611評(píng)論 2 353

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