iOS筆記( 啟動時間性能優(yōu)化)

應(yīng)用啟動環(huán)節(jié)熙参,我們大致分為2種啟動:即冷啟動(Cold Launch)和熱啟動(Warm Launch)场靴,針對優(yōu)化队丝,我們主要針對冷啟動玩祟。

知識點:打印啟動時間

通過添加環(huán)境變量可以打印出APP的啟動時間分析(Edit scheme -> Run -> Arguments)
DYLD_PRINT_STATISTICS設(shè)置為1
如果需要更詳細(xì)的信息腹缩,那就將DYLD_PRINT_STATISTICS_DETAILS設(shè)置為1

一般而言,大家把iOS冷啟動的過程定義為:從用戶點擊App圖標(biāo)開始到appDelegate didFinishLaunching方法執(zhí)行完成為止。這個過程主要分為兩個階段:

  • main()函數(shù)之前藏鹊,即操作系統(tǒng)加載App可執(zhí)行文件到內(nèi)存润讥,然后執(zhí)行一系列的加載&鏈接等工作,最后執(zhí)行至App的main()函數(shù)盘寡。

  • main()函數(shù)之后楚殿,即從main()開始,到appDelegate的didFinishLaunchingWithOptions方法執(zhí)行完畢竿痰。

然而脆粥,當(dāng)didFinishLaunchingWithOptions執(zhí)行完成時,用戶還沒有看到App的主界面影涉,也不能開始使用App变隔。例如在外賣App中,App還需要做一些初始化工作蟹倾,然后經(jīng)歷定位匣缘、首頁請求、首頁渲染等過程后鲜棠,用戶才能真正看到數(shù)據(jù)內(nèi)容并開始使用肌厨,我們認(rèn)為這個時候冷啟動才算完成。

冷啟動過程圖解

在調(diào)用main()函數(shù)之前豁陆,基本所有的工作都是由操作系統(tǒng)完成的柑爸,開發(fā)者能夠插手的地方不多,所以如果想要優(yōu)化這段時間献联,就必須先了解一下竖配,操作系統(tǒng)在main()之前做了什么。main()之前操作系統(tǒng)所做的工作就是把可執(zhí)行文件(Mach-O格式)加載到內(nèi)存空間里逆,然后加載動態(tài)鏈接庫dyld进胯,再執(zhí)行一系列動態(tài)鏈接操作和初始化操作的過程(加載、綁定原押、及初始化方法)胁镐。這方面的資料網(wǎng)上比較多,但重復(fù)性較高诸衔,此處附上一篇WWDC的Topic:Optimizing App Startup Time盯漂。

dyld

'dyld(dynamic link editor),Apple的動態(tài)鏈接器笨农,可以用來裝載Mach-O文件(可執(zhí)行文件就缆、動態(tài)庫等)

啟動APP時,dyld所做的事情有:
裝載APP的可執(zhí)行文件谒亦,同時會遞歸加載所有依賴的動態(tài)庫
當(dāng)dyld把可執(zhí)行文件竭宰、動態(tài)庫都裝載完畢后空郊,會通知Runtime進(jìn)行下一步的處理

Dyld各階段內(nèi)容

具體關(guān)于dyld的講解推薦dyld專題文章講的很細(xì)致。

Runtime 運(yùn)行時

啟動APP時切揭,runtime所做的事情有

調(diào)用map_images進(jìn)行可執(zhí)行文件內(nèi)容的解析和處理
在load_images中調(diào)用call_load_methods狞甚,調(diào)用所有Class和Category的+load方法
進(jìn)行各種objc結(jié)構(gòu)的初始化(注冊O(shè)bjc類 、初始化類對象等等)
調(diào)用C++靜態(tài)初始化器和attribute((constructor))修飾的函數(shù)

到此為止廓旬,可執(zhí)行文件和動態(tài)庫中所有的符號(Class哼审,Protocol,Selector孕豹,IMP涩盾,…)都已經(jīng)按格式成功加載到內(nèi)存中,被runtime 所管理

了解完main()之前的加載過程后励背,我們可以分析出一些影響mian函數(shù)之前消耗時間的因素:

  • 動態(tài)庫加載越多旁赊,啟動越慢。
  • ObjC類椅野,方法越多,啟動越慢籍胯。
  • ObjC的+load越多竟闪,啟動越慢。
  • C的constructor函數(shù)越多杖狼,啟動越慢炼蛤。
  • C++靜態(tài)對象越多,啟動越慢蝶涩。

代碼瘦身

隨著業(yè)務(wù)的迭代理朋,不斷有新的代碼加入,同時也會廢棄掉無用的代碼和資源文件绿聘,但是工程中經(jīng)常有無用的代碼和文件被遺棄在角落里嗽上,沒有及時被清理掉。這些無用的部分一方面增大了App的包體積熄攘,另一方便也拖慢了App的冷啟動速度兽愤,所以及時清理掉這些無用的代碼和資源十分有必要。

通過對Mach-O文件的了解挪圾,可以知道__TEXT:__objc_methname:中包含了代碼中的所有方法浅萧,而__DATA__objc_selrefs中則包含了所有被使用的方法的引用,通過取兩個集合的差集就可以得到所有未被使用的代碼哲思。核心方法如下洼畅,具體可以參考:objc_cover:

 def referenced_selectors(path):
    re_sel = re.compile("__TEXT:__objc_methname:(.+)") //獲取所有方法
    refs = set()
    lines = os.popen("/usr/bin/otool -v -s __DATA __objc_selrefs %s" % path).readlines() # ios & mac //真正被使用的方法
    for line in lines:
        results = re_sel.findall(line)
        if results:
            refs.add(results[0])
    return refs

+load優(yōu)化

目前iOS App中或多或少的都會寫一些+load方法,用于在App啟動執(zhí)行一些操作棚赔,+load方法在Initializers階段被執(zhí)行帝簇,但過多+load方法則會拖慢啟動速度徘郭,對于大中型的App更是如此。通過對App中+load的方法分析己儒,發(fā)現(xiàn)很多代碼雖然需要在App啟動時較早的時機(jī)進(jìn)行初始化崎岂,但并不需要在+load這樣非常靠前的位置闪湾,完全是可以延遲到App冷啟動后的某個時間節(jié)點冲甘,例如一些路由操作。

優(yōu)化耗時操作

在main()之后主要工作是各種啟動項的執(zhí)行途样,主界面的構(gòu)建江醇,例如TabBarVC,HomeVC等等何暇。資源的加載陶夜,如圖片I/O、圖片解碼裆站、archive文檔等条辟。這些操作中可能會隱含著一些耗時操作,靠單純閱讀非常難以發(fā)現(xiàn)宏胯,如何發(fā)現(xiàn)這些耗時點呢羽嫡?找到合適的工具就會事半功倍。

Time Profiler

Time Profiler是Xcode自帶的時間性能分析工具肩袍,它按照固定的時間間隔來跟蹤每一個線程的堆棧信息杭棵,通過統(tǒng)計比較時間間隔之間的堆棧狀態(tài),來推算某個方法執(zhí)行了多久氛赐,并獲得一個近似值魂爪。Time Profiler的使用方法網(wǎng)上有很多使用教程,這里我們也不過多介紹艰管,附上一篇使用文檔:Instruments Tutorial with Swift: Getting Started滓侍。

火焰圖

除了Time Profiler,火焰圖也是一個分析CPU耗時的利器蛙婴,相比于Time Profiler粗井,火焰圖更加清晰〗滞迹火焰圖分析的產(chǎn)物是一張調(diào)用棧耗時圖片浇衬,之所以稱為火焰圖,是因為整個圖形看起來就像一團(tuán)跳動的火焰餐济,火焰尖部是調(diào)用棧的棧頂耘擂,底部是棧底,縱向表示調(diào)用棧的深度絮姆,橫向表示消耗的時間醉冤。一個格子的寬度越大秩霍,越說明其可能是瓶頸。分析火焰圖主要就是看那些比較寬大的火苗蚁阳,特別留意那些類似“平頂山”的火苗铃绒。

列舉幾點具體優(yōu)化的方向


優(yōu)化方向

閃屏業(yè)務(wù)上優(yōu)化點

現(xiàn)在許多App在啟動時并不直接進(jìn)入首頁,而是會向用戶展示一個持續(xù)一小段時間的閃屏頁螺捐,如果使用恰當(dāng)颠悬,這個閃屏頁就能幫我們節(jié)省一些啟動時間。因為當(dāng)一個App比較復(fù)雜的時候定血,啟動時首次構(gòu)建App的UI就是一個比較耗時的過程赔癌,假定這個時間是0.2秒,如果我們是先構(gòu)建首頁UI澜沟,然后再在Window上加上這個閃屏頁灾票,那么冷啟動時,App就會實實在在地卡住0.2秒茫虽,但是如果我們是先把閃屏頁作為App的RootViewController刊苍,那么這個構(gòu)建過程就會很快。因為閃屏頁只有一個簡單的ImageView濒析,而這個ImageView則會向用戶展示一小段時間班缰,這時我們就可以利用這一段時間來構(gòu)建首頁UI了,一舉兩得悼枢。
TOGO途歌共享車客戶端就是使用的這種方案。

對于快速迭代的App脾拆,隨著業(yè)務(wù)復(fù)雜度的增加馒索,冷啟動時長會不可避免的增加。冷啟動流程也是一個比較復(fù)雜的過程名船,當(dāng)遇到冷啟動性能瓶頸時绰上,我們可以根據(jù)App自身的特點,配合工具的使用渠驼,從多方面蜈块、多角度進(jìn)行優(yōu)化。同時迷扇,優(yōu)化冷啟動存量問題只是冷啟動治理的第一步百揭,因為冷啟動性能問題并不是一日造成的,也不能簡單的通過一次優(yōu)化工作就能解決蜓席,我們需要通過合理的設(shè)計器一、規(guī)范的約束,來有效地管控性能問題的增量厨内,并通過持續(xù)的線上監(jiān)控來及時發(fā)現(xiàn)并修正性能問題祈秕,這樣才能夠長期保證良好的App冷啟動體驗渺贤。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市请毛,隨后出現(xiàn)的幾起案子志鞍,更是在濱河造成了極大的恐慌,老刑警劉巖方仿,帶你破解...
    沈念sama閱讀 221,198評論 6 514
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件固棚,死亡現(xiàn)場離奇詭異,居然都是意外死亡兼丰,警方通過查閱死者的電腦和手機(jī)玻孟,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,334評論 3 398
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來鳍征,“玉大人黍翎,你說我怎么就攤上這事⊙薮裕” “怎么了匣掸?”我有些...
    開封第一講書人閱讀 167,643評論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長氮双。 經(jīng)常有香客問我碰酝,道長,這世上最難降的妖魔是什么戴差? 我笑而不...
    開封第一講書人閱讀 59,495評論 1 296
  • 正文 為了忘掉前任送爸,我火速辦了婚禮,結(jié)果婚禮上暖释,老公的妹妹穿的比我還像新娘袭厂。我一直安慰自己,他們只是感情好球匕,可當(dāng)我...
    茶點故事閱讀 68,502評論 6 397
  • 文/花漫 我一把揭開白布纹磺。 她就那樣靜靜地躺著,像睡著了一般亮曹。 火紅的嫁衣襯著肌膚如雪橄杨。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,156評論 1 308
  • 那天照卦,我揣著相機(jī)與錄音式矫,去河邊找鬼。 笑死役耕,一個胖子當(dāng)著我的面吹牛衷佃,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播蹄葱,決...
    沈念sama閱讀 40,743評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼氏义,長吁一口氣:“原來是場噩夢啊……” “哼锄列!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起惯悠,我...
    開封第一講書人閱讀 39,659評論 0 276
  • 序言:老撾萬榮一對情侶失蹤邻邮,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后克婶,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體筒严,經(jīng)...
    沈念sama閱讀 46,200評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,282評論 3 340
  • 正文 我和宋清朗相戀三年情萤,在試婚紗的時候發(fā)現(xiàn)自己被綠了鸭蛙。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,424評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡筋岛,死狀恐怖娶视,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情睁宰,我是刑警寧澤肪获,帶...
    沈念sama閱讀 36,107評論 5 349
  • 正文 年R本政府宣布,位于F島的核電站柒傻,受9級特大地震影響孝赫,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜红符,卻給世界環(huán)境...
    茶點故事閱讀 41,789評論 3 333
  • 文/蒙蒙 一青柄、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧预侯,春花似錦刹前、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,264評論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽祖今。三九已至校坑,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間千诬,已是汗流浹背耍目。 一陣腳步聲響...
    開封第一講書人閱讀 33,390評論 1 271
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留徐绑,地道東北人邪驮。 一個月前我還...
    沈念sama閱讀 48,798評論 3 376
  • 正文 我出身青樓,卻偏偏與公主長得像傲茄,于是被迫代替她去往敵國和親毅访。 傳聞我的和親對象是個殘疾皇子沮榜,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,435評論 2 359