App優(yōu)化

一、啟動(dòng)時(shí)間測量(優(yōu)化啟動(dòng)時(shí)間)

1梢褐、main函數(shù)前執(zhí)行的時(shí)間

在此階段系統(tǒng)做的任務(wù)為:

1.1. 加載應(yīng)用的可執(zhí)行文件

1.2. 加載動(dòng)態(tài)鏈接庫加載器dyld(dynamic loader)

1.3. dyld遞歸加載應(yīng)用所有依賴的dylib(dynamic library 動(dòng)態(tài)鏈接庫)

測試方法:在 Xcode 中 Edit scheme -> Run -> Auguments 將環(huán)境變量DYLD_PRINT_STATISTICS 設(shè)為1 辛块。然后就可以看到控制臺(tái)打印出main之前的時(shí)間

打印結(jié)果如下:(單位:毫秒)

Total pre-main time: 675.00 milliseconds (100.0%)

dylib loading time:? 42.79 milliseconds (6.3%)

rebase/binding time:? 39.88 milliseconds (5.9%)

ObjC setup time: 161.19 milliseconds (23.8%)

initializer time: 431.02 milliseconds (63.8%)

slowest intializers :

libSystem.B.dylib :? 10.13 milliseconds (1.5%)

libMainThreadChecker.dylib :? 21.36 milliseconds (3.1%)

libglInterpose.dylib :? 86.58 milliseconds (12.8%)

libMTLInterpose.dylib :? 21.31 milliseconds (3.1%)

ModelIO :? 17.24 milliseconds (2.5%)

?XXX : 371.80 milliseconds (55.0%)

Load dylibs

這一階段dyld會(huì)分析應(yīng)用依賴的dylib围俘,找到其mach-o文件蛇损,打開和讀取這些文件并驗(yàn)證其有效性豹绪,接著會(huì)找到代碼簽名注冊到內(nèi)核,最后對dylib的每一個(gè)segment調(diào)用mmap()镇防。

一般情況下纽门,iOS應(yīng)用會(huì)加載100-400個(gè)dylibs,其中大部分是系統(tǒng)庫营罢,這部分dylib的加載系統(tǒng)已經(jīng)做了優(yōu)化。

所以饼齿,依賴的dylib越少越好饲漾。在這一步,我們可以做的優(yōu)化有:

盡量不使用內(nèi)嵌(embedded)的dylib缕溉,加載內(nèi)嵌dylib性能開銷較大

合并已有的dylib和使用靜態(tài)庫(static archives)考传,減少dylib的使用個(gè)數(shù)

懶加載dylib,但是要注意dlopen()可能造成一些問題证鸥,且實(shí)際上懶加載做的工作會(huì)更多

?Rebase/Bind

在dylib的加載過程中僚楞,系統(tǒng)為了安全考慮,引入了ASLR(Address Space Layout Randomization)技術(shù)和代碼簽名枉层。由于ASLR的存在泉褐,鏡像(Image,包括可執(zhí)行文件鸟蜡、dylib和bundle)會(huì)在隨機(jī)的地址上加載膜赃,和之前指針指向的地址(preferred_address)會(huì)有一個(gè)偏差(slide),dyld需要修正這個(gè)偏差揉忘,來指向正確的地址跳座。

Rebase在前端铛,Bind在后,Rebase做的是將鏡像讀入內(nèi)存疲眷,修正鏡像內(nèi)部的指針禾蚕,性能消耗主要在IO。Bind做的是查詢符號表狂丝,設(shè)置指向鏡像外部的指針换淆,性能消耗主要在CPU計(jì)算。所以美侦,指針數(shù)量越少越好产舞。

在這一步,我們可以做的優(yōu)化有:

減少ObjC類(class)菠剩、方法(selector)易猫、分類(category)的數(shù)量

減少C++虛函數(shù)的的數(shù)量(創(chuàng)建虛函數(shù)表有開銷)

使用Swift structs(內(nèi)部做了優(yōu)化,符號數(shù)量更少)

Objc setup

大部分ObjC初始化工作已經(jīng)在Rebase/Bind階段做完了具壮,這一步dyld會(huì)注冊所有聲明過的ObjC類准颓,將分類插入到類的方法列表里,再檢查每個(gè)selector的唯一性棺妓。

在這一步倒沒什么優(yōu)化可做的攘已,Rebase/Bind階段優(yōu)化好了,這一步的耗時(shí)也會(huì)減少怜跑。

?Initializers

到了這一階段样勃,dyld開始運(yùn)行程序的初始化函數(shù),調(diào)用每個(gè)Objc類和分類的+load方法性芬,調(diào)用C/C++ 中的構(gòu)造器函數(shù)(用attribute((constructor))修飾的函數(shù))峡眶,和創(chuàng)建非基本類型的C++靜態(tài)全局變量。Initializers階段執(zhí)行完后植锉,dyld開始調(diào)用main()函數(shù)辫樱。

在這一步,我們可以做的優(yōu)化有:?

1.少在類的+load方法里做事情俊庇,盡量把這些事情推遲到+initiailize

2.減少構(gòu)造器函數(shù)個(gè)數(shù)狮暑,在構(gòu)造器函數(shù)里少做些事情

3.減少C++靜態(tài)全局變量的個(gè)數(shù)

2、main函數(shù)后到didlaunchoption或者到RootVC的Viewdidload方法

2.1. dyld調(diào)用main()?

2.2. 調(diào)用UIApplicationMain()?

2.3. 調(diào)用applicationWillFinishLaunching

2.4. 調(diào)用didFinishLaunchingWithOptions

測試方法:

在main函數(shù)中聲明 ?CFAbsoluteTime startTime; ?startTime = CFAbsoluteTimeGetCurrent();//記錄進(jìn)入main函數(shù)時(shí)的時(shí)間

在RootViewController中聲明extern??CFAbsoluteTime startTime;在viewdidload中計(jì)算時(shí)差:CFAbsoluteTimeGetCurrent() - startTime

這一階段的優(yōu)化主要是減少didFinishLaunchingWithOptions方法里的工作辉饱,在didFinishLaunchingWithOptions方法里搬男,我們會(huì)創(chuàng)建應(yīng)用的window,指定其rootViewController彭沼,調(diào)用window的makeKeyAndVisible方法讓其可見止后。由于業(yè)務(wù)需要,我們會(huì)初始化各個(gè)二方/三方庫,設(shè)置系統(tǒng)UI風(fēng)格译株,檢查是否需要顯示引導(dǎo)頁瓜喇、是否需要登錄、是否有新版本等歉糜,由于歷史原因乘寒,這里的代碼容易變得比較龐大,啟動(dòng)耗時(shí)難以控制匪补。

所以伞辛,滿足業(yè)務(wù)需要的前提下,didFinishLaunchingWithOptions在主線程里做的事情越少越好夯缺。在這一步蚤氏,我們可以做的優(yōu)化有:

1.梳理各個(gè)二方/三方庫,找到可以延遲加載的庫踊兜,做延遲加載處理竿滨,比如放到首頁控制器的2.viewDidAppear方法里。

3.梳理業(yè)務(wù)邏輯捏境,把可以延遲執(zhí)行的邏輯于游,做延遲執(zhí)行處理。比如檢查新版本垫言、注冊推送通知等邏輯贰剥。

4.避免復(fù)雜/多余的計(jì)算。

5.避免在首頁控制器的viewDidLoad和viewWillAppear做太多事情筷频,這2個(gè)方法執(zhí)行完蚌成,首頁控制器才能顯示,部分可以延遲創(chuàng)建的視圖應(yīng)做延遲創(chuàng)建/懶加載處理凛捏。

6.采用性能更好的API担忧。

7.首頁控制器用純代碼方式來構(gòu)建。

二葵袭、循環(huán)引用(如下常見舉例)

1、對象相互引用無法釋放

2乖菱、block(block里面引用自身對象需要用__weak typedeof(self) weakSelf = self)

? ? ? VC1——》push到VC2

? ? ? VC2中命名block

? ? ?Self.block = ^{

執(zhí)行 5s后打印weakSelf.str

};

若在5s內(nèi)從VC2返回VC1坡锡,則VC2的block執(zhí)行的內(nèi)容結(jié)果為null

若在5s后從VC2返回VC1,則VC2的block執(zhí)行的結(jié)果為真實(shí)打印出self.str的值

從而為了避免上面的情況的發(fā)生則需要用__Strong來修飾self窒所。

三鹉勒、內(nèi)存泄漏檢測

一般4種方法

1、靜態(tài)檢測analyze

2吵取、instrument

3禽额、leaks(三方工具M(jìn)LeaksFinder)

4、dealloc方法檢測頁面銷毀的時(shí)候是否釋放對應(yīng)的對象

四、算法復(fù)雜度&函數(shù)性能測試(結(jié)合單元測試)

具體可以參考單元測試?yán)锩娴臏y試代碼執(zhí)行時(shí)間方法脯倒。

五实辑、imageNamed:和imageWithContentsOfFile:加載圖片的選擇

imageNamed:

這個(gè)方法用一個(gè)指定的名字在系統(tǒng)緩存中查找并返回一個(gè)圖片對象如果它存在的話。如果緩存中沒有找到相應(yīng)的圖片藻丢,這個(gè)方法從指定的文檔中加載然后緩存并返回這個(gè)對象剪撬。因此imageNamed的優(yōu)點(diǎn)是當(dāng)加載時(shí)會(huì)緩存圖片。所以當(dāng)圖片會(huì)頻繁的使用時(shí)悠反,那么用imageNamed的方法會(huì)比較好残黑。例如:你需要在 一個(gè)TableView里的TableViewCell里都加載同樣一個(gè)圖標(biāo),那么用imageNamed加載圖像效率很高斋否。系統(tǒng)會(huì)把那個(gè)圖標(biāo)Cache到內(nèi)存梨水,在TableViewCell里每次利用那個(gè)圖 像的時(shí)候,只會(huì)把圖片指針指向同一塊內(nèi)存茵臭。正是因此使用imageNamed會(huì)緩存圖片疫诽,即將圖片的數(shù)據(jù)放在內(nèi)存中,iOS的內(nèi)存非常珍貴并且在內(nèi)存消耗過大時(shí)笼恰,會(huì)強(qiáng)制釋放內(nèi)存踊沸,即會(huì)遇到memory warnings。而在iOS系統(tǒng)里面釋放圖像的內(nèi)存是一件比較麻煩的事情社证,有可能會(huì)造成內(nèi)存泄漏逼龟。例如:當(dāng)一 個(gè)UIView對象的animationImages是一個(gè)裝有UIImage對象動(dòng)態(tài)數(shù)組NSMutableArray,并進(jìn)行逐幀動(dòng)畫追葡。當(dāng)使用imageNamed的方式加載圖像到一個(gè)動(dòng)態(tài)數(shù)組NSMutableArray腺律,這將會(huì)很有可能造成內(nèi)存泄露。原因很顯然的宜肉。

imageWithContentsOfFile:

僅加載圖片匀钧,圖像數(shù)據(jù)不會(huì)緩存。因此對于較大的圖片以及使用情況較少時(shí)谬返,那就可以用該方法之斯,降低內(nèi)存消耗。

六遣铝、本地圖片資源的優(yōu)化

1佑刷、清除與項(xiàng)目無關(guān)的圖片資源,比如測試階段使用到酿炸、前期使用到瘫絮、前后期更換,上線以后就沒有用途了填硕, 刪除這些圖片麦萤。

2鹿鳖、對項(xiàng)目所有的引用圖片資源統(tǒng)一進(jìn)行壓縮后再使用。(https://tinypng.com)可以在這個(gè)網(wǎng)站進(jìn)行圖片壓縮壮莹。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末翅帜,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子垛孔,更是在濱河造成了極大的恐慌藕甩,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,948評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件周荐,死亡現(xiàn)場離奇詭異狭莱,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)概作,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,371評論 3 385
  • 文/潘曉璐 我一進(jìn)店門腋妙,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人讯榕,你說我怎么就攤上這事骤素。” “怎么了愚屁?”我有些...
    開封第一講書人閱讀 157,490評論 0 348
  • 文/不壞的土叔 我叫張陵济竹,是天一觀的道長。 經(jīng)常有香客問我霎槐,道長送浊,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,521評論 1 284
  • 正文 為了忘掉前任丘跌,我火速辦了婚禮袭景,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘闭树。我一直安慰自己耸棒,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,627評論 6 386
  • 文/花漫 我一把揭開白布报辱。 她就那樣靜靜地躺著与殃,像睡著了一般。 火紅的嫁衣襯著肌膚如雪碍现。 梳的紋絲不亂的頭發(fā)上幅疼,一...
    開封第一講書人閱讀 49,842評論 1 290
  • 那天,我揣著相機(jī)與錄音鸵赫,去河邊找鬼衣屏。 笑死躏升,一個(gè)胖子當(dāng)著我的面吹牛辩棒,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 38,997評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼一睁,長吁一口氣:“原來是場噩夢啊……” “哼钻弄!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起者吁,我...
    開封第一講書人閱讀 37,741評論 0 268
  • 序言:老撾萬榮一對情侶失蹤窘俺,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后复凳,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體瘤泪,經(jīng)...
    沈念sama閱讀 44,203評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,534評論 2 327
  • 正文 我和宋清朗相戀三年育八,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了对途。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,673評論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡髓棋,死狀恐怖实檀,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情按声,我是刑警寧澤膳犹,帶...
    沈念sama閱讀 34,339評論 4 330
  • 正文 年R本政府宣布,位于F島的核電站签则,受9級特大地震影響须床,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜怀愧,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,955評論 3 313
  • 文/蒙蒙 一侨颈、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧芯义,春花似錦哈垢、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,770評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至绑警,卻和暖如春求泰,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背计盒。 一陣腳步聲響...
    開封第一講書人閱讀 32,000評論 1 266
  • 我被黑心中介騙來泰國打工渴频, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人北启。 一個(gè)月前我還...
    沈念sama閱讀 46,394評論 2 360
  • 正文 我出身青樓卜朗,卻偏偏與公主長得像拔第,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子场钉,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,562評論 2 349

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