iOS App性能優(yōu)化

iOS App性能優(yōu)化

29 MAY 2013 on iOS, Performance

iOS App的性能關(guān)注點(diǎn)

雖然iPhone的機(jī)能越來越好相满,但是app的功能也越來越復(fù)雜捌显,性能從來都是移動(dòng)開發(fā)的核心關(guān)注點(diǎn)之一。我們說一個(gè)app性能好字管,不是簡單指感覺運(yùn)行速度快,而應(yīng)該是指應(yīng)用啟動(dòng)快速衷敌、UI反饋響應(yīng)及時(shí)鳖悠、列表滾動(dòng)操作流暢、內(nèi)存使用合理溶锭,當(dāng)然更不能隨隨便便Crash啦宝恶。工程師開發(fā)應(yīng)用時(shí)除了在設(shè)計(jì)上要避免性能“坑”的出現(xiàn),在實(shí)際遇到“坑”時(shí)也要能很快定位原因所在趴捅。定位性能問題原因當(dāng)然不能靠猜垫毙,合理的方法是使用工具測量評估出投資回報(bào)最高的問題點(diǎn),然后再加以優(yōu)化拱绑。

本文會(huì)從以下幾點(diǎn)介紹如何分析和優(yōu)化iOS app的性能:啟動(dòng)時(shí)間综芥、用戶響應(yīng)、內(nèi)存猎拨、圖形動(dòng)畫膀藐、文件和網(wǎng)絡(luò)I/O。其中會(huì)用到Apple出品的性能分析神器“Instruments”红省。

啟動(dòng)時(shí)間

應(yīng)用啟動(dòng)時(shí)間長短對用戶第一次體驗(yàn)至關(guān)重要额各,同時(shí)系統(tǒng)對應(yīng)用的啟動(dòng)、恢復(fù)等狀態(tài)的運(yùn)行時(shí)間也有嚴(yán)格的要求类腮,在應(yīng)用超時(shí)的情況下系統(tǒng)會(huì)直接關(guān)閉應(yīng)用。以下是幾個(gè)常見場景下系統(tǒng)對app運(yùn)行時(shí)間的要求:

Launch 20秒

Resume 10秒

Suspend 10秒

Quit 6秒

Background Task 10分鐘

要獲取準(zhǔn)確的app啟動(dòng)所需時(shí)間蛉加,最簡單的方法時(shí)首先在main.c中添加如下代碼:

CFAbsoluteTime StartTime;

int main(int argc, char **argv) {

StartTime = CFAbsoluteTimeGetCurrent();

然后在AppDelegate的回調(diào)方法application:didFinishLaunchingWithOptions中添加:

dispatch_async(dispatch_get_main_queue(), ^{

NSLog(@”Lauched in %f seconds.”,? (CFAbsoluteTimeGetCurrent() – StartTime));

});

可能你會(huì)覺得為什么這樣可拿到系統(tǒng)啟動(dòng)的時(shí)間蚜枢,因?yàn)檫@個(gè)dispatch_async中提交的工作會(huì)在app主線程啟動(dòng)后的下一個(gè)run lopp中運(yùn)行,此時(shí)app已經(jīng)完成了載入并且將要顯示第一幀畫面针饥,也就是系統(tǒng)會(huì)運(yùn)行到-[UIApplication _reportAppLaunchFinished]之前厂抽。下圖是用Instruments工具Time Profiler跑的調(diào)用棧,Instruments的使用方法建議看WWDC中與performance相關(guān)的session錄像丁眼,文字寫起來太單薄不夠直觀哈筷凤。

從圖中我們可以看到在系統(tǒng)調(diào)用[UIApplication _reportAppLaunchFinished]之前完成了系統(tǒng)回調(diào)application:didFinishLaunchingWithOptions。

App的啟動(dòng)會(huì)包括以下幾個(gè)部分(來自WWDC 2012 Session 235):

1)鏈接和載入:可以在Time Profile中顯示dyld載入庫函數(shù),庫會(huì)被映射到地址空間藐守,同時(shí)完成綁定以及靜態(tài)初始化挪丢。

2)UIKit初始化:如果應(yīng)用的Root View Controller是由XIB實(shí)現(xiàn)的,也會(huì)在啟動(dòng)時(shí)被初始化卢厂。

3)應(yīng)用回調(diào):調(diào)用UIApplicationDeleagte的回調(diào):application:didFinishLaunchingWithOptions

4)第一次Core Animation調(diào)用:在啟動(dòng)后的方法-[UIApplication _resportAppLaunchFinished]中調(diào)用CA::Transaction::commit實(shí)現(xiàn)第一幀畫面的繪制乾蓬。

如果你的程序啟動(dòng)很慢,能 做的首先是將與顯示第一屏畫面無關(guān)的操作放到之后執(zhí)行慎恒;如果是用XIB文件load第一屏任内,XIB文件中的View層也要如果扁平,不要有太多圖層融柬。

用戶響應(yīng)

如何能夠讓用戶覺得你的app響應(yīng)迅速呢死嗦?當(dāng)然是app用戶所觸發(fā)的操作都能得到立刻響應(yīng),即用戶事件(User Event)能夠被主線程的run loop及時(shí)處理粒氧。什么是run loop越除?可以想象成一個(gè)處理事件的select多路復(fù)用。主線程中的run loop當(dāng)然主要是為了處理用戶產(chǎn)生的事件啦靠欢,例如點(diǎn)擊廊敌、滾動(dòng)等。以后我們會(huì)詳細(xì)聊聊run loop這個(gè)讓人迷惑的東東门怪。

要讓主線程的run loop更好的響應(yīng)用戶事件骡澈,工程師應(yīng)該盡量減少主線程干重活的時(shí)間,尤其是讀文件啊掷空,網(wǎng)絡(luò)操作啊肋殴,大量運(yùn)算啊這類重活,如果是阻塞操作坦弟,那就更是大忌了护锤。我們可以用多線程(NSThread、NSOperationQueue, GCD酿傍,下一篇Blog就會(huì)聊到這多線程)將重活移出主線程烙懦,這屬于顯式并發(fā)。還有種隱式并發(fā)赤炒,例如view和layer的動(dòng)畫氯析、layer的繪制以及PNG圖片的解碼都是在另一個(gè)子線程中執(zhí)行的。除了使用多線程技術(shù)減輕主線程的負(fù)擔(dān)外莺褒,減少主線程中阻塞也是提升用戶體驗(yàn)的一個(gè)方法掩缓。使用Instruments中Time Profiler工具中的"Recod thread waiting"選項(xiàng)可以統(tǒng)計(jì)出app運(yùn)行時(shí)各個(gè)線程中的阻塞系統(tǒng)調(diào)用情況,例如文件讀寫read/write遵岩,網(wǎng)絡(luò)讀寫send/recv你辣,加鎖psynchmutexwait等。Instruments中的System Trace工具則能夠記錄所有的底層系統(tǒng)調(diào)用。

內(nèi)存

內(nèi)存問題從來都是iOS app的老大難問題舍哄,搞不好程序就爆了宴凉。由于iOS系統(tǒng)沒有Swap文件(知道為啥不?留給懸念)蠢熄,在內(nèi)存不足時(shí)會(huì)將只讀數(shù)據(jù)(例如code page)從內(nèi)存中移出跪解,需要的時(shí)候再從disk上讀如內(nèi)存;可讀寫數(shù)據(jù)不會(huì)被系統(tǒng)從內(nèi)存中移出签孔,然而如果占用的內(nèi)存達(dá)到一個(gè)閾值叉讥,系統(tǒng)會(huì)發(fā)出相應(yīng)的通知和回調(diào)讓應(yīng)用release對象以回收內(nèi)存,如果仍然不能減少內(nèi)存使用量饥追,系統(tǒng)會(huì)直接關(guān)閉應(yīng)用图仓。尤其是iOS 5.0之后,如果你的app收到了memory warning但绕,那么腦袋也是和其他app一樣放在了案板上救崔,隨時(shí)有可能被kill掉,并不是說一定會(huì)先Kill掉在后臺的app捏顺。

App使用的內(nèi)存除了我們在堆上分配的內(nèi)存外(+[NSobject alloc]/malloc)六孵,還會(huì)有更多使用內(nèi)存的地方,比如代碼和全局?jǐn)?shù)據(jù)(TEXT和DATA)幅骄,線程棧劫窒,圖片,view 的layer backing store等等拆座。因此處理內(nèi)存問題主巍,絕不僅僅是我們開發(fā)app時(shí)盡量少申請內(nèi)存那么簡單。

現(xiàn)在有了超炫的ARC挪凑,內(nèi)存問題相對少了很多孕索,開發(fā)效率也得到了提高。但是很多公司的項(xiàng)目仍然由于歷史原因采用了手動(dòng)管理內(nèi)存躏碳,該做的活還是少不了搞旭。Xcode自帶的靜態(tài)分析功能可以幫你提前發(fā)現(xiàn)一些問題,然而有些內(nèi)存問題是無法用靜態(tài)分析來發(fā)現(xiàn)的菇绵,例如我們不斷使用內(nèi)存沒有及時(shí)釋放的問題肄渗,就無法使用靜態(tài)分析器分析出來。此時(shí)可以使用Instruments的Allocations和Leaks工具來檢查運(yùn)行時(shí)的的內(nèi)存使用以及泄露問題脸甘。

Allocations工具可以很直觀的反應(yīng)app的內(nèi)存使用情況恳啥,還有個(gè)很贊“Mark Heap”功能偏灿,在上圖左邊下半部分中的Heapshot Analysis中丹诀。例如你在進(jìn)入一個(gè)頁面前點(diǎn)擊一下“Mark Heap”,然后再退回上一頁面點(diǎn)擊一下“Mark Heap”,如果你在進(jìn)出這個(gè)頁面里所申請的內(nèi)存都得到了合理的釋放铆遭,那么堆的內(nèi)存增長量就應(yīng)該降至0(見上圖右下部分)硝桩。

另一種嚴(yán)重的內(nèi)存使用問題是引用了已經(jīng)釋放的內(nèi)存,直接導(dǎo)致應(yīng)用崩潰枚荣,而Allocation有一個(gè)選項(xiàng)Enable NSZombie detection能夠在應(yīng)用使用已經(jīng)釋放的內(nèi)存時(shí)標(biāo)注出來碗脊,同時(shí)顯示錯(cuò)誤發(fā)生的調(diào)用棧信息。這為解決問題提供了最直接的幫助橄妆,當(dāng)然缺點(diǎn)是必須能夠重現(xiàn)EXECBADACCESS錯(cuò)誤衙伶。

工具Leaks可以在應(yīng)用運(yùn)行時(shí)直接標(biāo)示出存在內(nèi)存泄露的代碼,如果發(fā)生了內(nèi)存泄露害碾,可以從泄露詳細(xì)信息中查看泄露的具體對象以及方法調(diào)用棧矢劲,大部分問題還是很好解決的。

圖形和動(dòng)畫

圖形性能對用戶體驗(yàn)有直接的影響慌随,Instruments中的Core Animation工具用于測量物理機(jī)上的圖形性能芬沉,通過視圖的刷新頻率大小來判斷應(yīng)用的圖形性能。例如一個(gè)復(fù)雜的列表滾動(dòng)時(shí)它的刷新率應(yīng)該努力趨近于60fps才能讓用戶覺得夠流暢阁猜,從這個(gè)數(shù)字也可以算出run loop最長的響應(yīng)時(shí)間應(yīng)該是16毫秒丸逸。

啟動(dòng)Instruments的Core Animation工具后可以發(fā)現(xiàn)左下部分有一堆選項(xiàng),我們來逐個(gè)介紹:

1) Color Blended Layers

Instruments可以在物理機(jī)上顯示出被混合的圖層Blended Layer(用紅色標(biāo)注)剃袍,Blended Layer是因?yàn)檫@些Layer是透明的(Transparent)黄刚,系統(tǒng)在渲染這些view時(shí)需要將該view和下層view混合(Blend)后才能計(jì)算出該像素點(diǎn)的實(shí)際顏色,如果這種blended layer很多笛园,那么在滾動(dòng)列表時(shí)就甭想有流暢的效果隘击。

解決blended layer問題也很簡單,檢查紅色區(qū)域view的opaque屬性研铆,記得設(shè)置成YES埋同;檢查backgroundColor屬性是不是[UIColor clearColor],要知道背景顏色為clear color那可是圖形性能的大敵棵红,基本意味著blended layer是跑不了的了凶赁,為什么?自己思考一下:)

2) Color Hits Green and Misses Red

很多視圖Layer由于Shadow逆甜、Mask和Gradient等原因渲染很高虱肄,因此UIKit提供了API用于緩存這些Layer:[layer setShouldRasterize:YES],系統(tǒng)會(huì)將這些Layer緩存成Bitmap位圖供渲染使用交煞,如果失效時(shí)便丟棄這些Bitmap重新生成咏窿。圖層Rasterization柵格化好處是對刷新率影響較小,壞處是刪格化處理后的Bitmap緩存需要占用內(nèi)存素征,而且當(dāng)圖層需要縮放時(shí)集嵌,要對刪格化后的Bitmap做額外計(jì)算萝挤。

使用這個(gè)選項(xiàng)后時(shí),如果Rasterized的Layer失效根欧,便會(huì)標(biāo)注為紅色怜珍,如果有效標(biāo)注為綠色。當(dāng)測試的應(yīng)用頻繁閃現(xiàn)出紅色標(biāo)注圖層時(shí)凤粗,表明對圖層做的Rasterization作用不大酥泛。

3) Color Misaligned Images

Misaligned Image表示要繪制的點(diǎn)無法直接映射到頻幕上的像素點(diǎn),此時(shí)系統(tǒng)需要對相鄰的像素點(diǎn)做anti-aliasing反鋸齒計(jì)算嫌拣,增加了圖形負(fù)擔(dān)柔袁,通常這種問題出在對某些View的Frame重新計(jì)算和設(shè)置時(shí)產(chǎn)生的。

上圖中被標(biāo)注為黃色的圖層异逐,這是由于圖層顯示的是被縮放后的圖片瘦馍,如果這些圖片是通過網(wǎng)絡(luò)下載的,可以通過程序更新為確定的繪制大小來解決应役。還有些系統(tǒng)Navigation Bar和Tool Bar的背景圖片使用的是拉伸(Streched)圖片情组,也會(huì)被表示為黃色,這是屬于正常情況箩祥,通常無需修改院崇。這種問題一般對性能影響不大,而是可能會(huì)在邊緣處虛化袍祖。

(4) Color Offscreen-Rendered Yellow

Offscreen-Rendering離屏渲染意思是iOS要顯示一個(gè)視圖時(shí)底瓣,需要先在后臺用CPU計(jì)算出視圖的Bitmap,再交給GPU做Onscreen-Rendering顯示在屏幕上蕉陋,因?yàn)轱@示一個(gè)視圖需要兩次計(jì)算捐凭,所以這種Offscreen-Rendering會(huì)導(dǎo)致app的圖形性能下降。

大部分Offscreen-Rendering都是和視圖Layer的Shadow和Mask相關(guān)凳鬓,下列情況會(huì)導(dǎo)致視圖的Offscreen-Rendering:

使用Core Graphics (CG開頭的類)茁肠。

使用drawRect()方法,即使為空缩举。

將CALayer的屬性shouldRasterize設(shè)置為YES垦梆。

使用了CALayer的setMasksToBounds(masks)和setShadow*(shadow)方法。

在屏幕上直接顯示文字仅孩,包括Core Text托猩。

設(shè)置UIViewGroupOpacity。

這篇博文Designing for iOS: Graphics & Performance對offsreen以及圖形性能有個(gè)很棒的介紹辽慕,

(5) Color Copied Images

Copied Image選項(xiàng)可以標(biāo)注應(yīng)用繪制時(shí)被Core Animation復(fù)制的圖片京腥,標(biāo)注成藍(lán)綠色。雖然我在運(yùn)行時(shí)遇到過溅蛉,不過個(gè)人感覺對圖形性能影響不大公浪。

(6) Color Immediately摆尝,F(xiàn)lash Updated Regions, Color OpenGL Fast Path Blue

Color Immediately選項(xiàng)表示Instruments在做color-flush操作時(shí)取消10毫秒的延時(shí)因悲。

Flash Updated Regions選項(xiàng)用于用紅色示標(biāo)示出在屏幕上使用GPU計(jì)算繪制的圖層。

Color OpenGL Fast Path Blue選項(xiàng)用于用藍(lán)色標(biāo)示出在屏幕上由OpenGL compositor繪制的內(nèi)容勺爱。

這三個(gè)選項(xiàng)對圖形性能的分析意義較小晃琳,通常僅作為參考。

文件和網(wǎng)絡(luò)I/O

如果需要對app的文件和網(wǎng)絡(luò)I/O情況做分析琐鲁,可以用到這三個(gè)Instruments工具System Usage卫旱、File Activity和Network。

工具System Usage可以統(tǒng)計(jì)出運(yùn)行狀態(tài)下應(yīng)用的文件和網(wǎng)絡(luò)IO操作數(shù)據(jù)围段。例如我們發(fā)現(xiàn)應(yīng)用啟動(dòng)后又一個(gè)峰值顾翼,這可能存在問題,我們可以利用System Usage工具的詳細(xì)信息欄查看應(yīng)用是由于對哪些文件的讀寫操作導(dǎo)致了峰值奈泪。

工具File Activity只能在模擬器中運(yùn)行适贸,因此數(shù)據(jù)采集可能不是非常準(zhǔn)確。它同樣可以詳細(xì)給出讀取的文件屬性涝桅、大小拜姿、載入時(shí)間等信息,適合與System Usage配合使用冯遂。

Network工具則可以采集到應(yīng)用的TCP/IP和UDP的使用信息(傳輸?shù)臄?shù)據(jù)量蕊肥、當(dāng)前所有TCP連接等),用得不多蛤肌,做網(wǎng)絡(luò)使用狀況分析時(shí)用用還行壁却。

更多閱讀

涉及iOS App性能的知識很多,上面只是冰山一角裸准,重點(diǎn)推薦WWDC的session展东。

WWDC 2012:

406: Adopting Automatic Reference Counting

238: iOS App Performance: Graphics and Animations

242: iOS App Performance: Memory

235: iOS App Performance: Responsiveness

409: Learning Instruments

706: Networking Best Practices

514: OpenGL ES Tools and Techniques

506: Optimizing 2D Graphics and Animation Performance

601: Optimizing Web Content in UIWebViews and Websites on iOS

225: Up and Running: Making a Great Impression with Every Launch

WWDC 2011:

105: Polishing Your App: Tips and tricks to improve the responsiveness and performance

121: Understanding UIKit Rendering

131 performance optimization on iphone os

308: Blocks and Grand Central Dispatch in Practice

323: Introducing Automatic Reference Counting

312: iOS Performance and Power Optimization with Instruments

還有幾篇不錯(cuò)的blog:

http://oleb.net/blog/2011/11/ios5-tech-talk-michael-jurewitz-on-performance-measurement/

http://eng.pulse.me/tips-for-improving-performance-of-your-ios-application/

http://robots.thoughtbot.com/post/36591648724/designing-for-ios-graphics-performance

http://www.touchwonders.com/en/how-to-make-your-apps-feel-responsive-and-fast-part-2/

comments powered by Disqus

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市炒俱,隨后出現(xiàn)的幾起案子琅锻,更是在濱河造成了極大的恐慌,老刑警劉巖向胡,帶你破解...
    沈念sama閱讀 206,602評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件恼蓬,死亡現(xiàn)場離奇詭異,居然都是意外死亡僵芹,警方通過查閱死者的電腦和手機(jī)处硬,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,442評論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來拇派,“玉大人荷辕,你說我怎么就攤上這事凿跳。” “怎么了疮方?”我有些...
    開封第一講書人閱讀 152,878評論 0 344
  • 文/不壞的土叔 我叫張陵控嗜,是天一觀的道長。 經(jīng)常有香客問我骡显,道長疆栏,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,306評論 1 279
  • 正文 為了忘掉前任惫谤,我火速辦了婚禮壁顶,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘溜歪。我一直安慰自己若专,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,330評論 5 373
  • 文/花漫 我一把揭開白布蝴猪。 她就那樣靜靜地躺著调衰,像睡著了一般。 火紅的嫁衣襯著肌膚如雪自阱。 梳的紋絲不亂的頭發(fā)上窖式,一...
    開封第一講書人閱讀 49,071評論 1 285
  • 那天,我揣著相機(jī)與錄音动壤,去河邊找鬼萝喘。 笑死,一個(gè)胖子當(dāng)著我的面吹牛琼懊,可吹牛的內(nèi)容都是我干的阁簸。 我是一名探鬼主播,決...
    沈念sama閱讀 38,382評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼哼丈,長吁一口氣:“原來是場噩夢啊……” “哼启妹!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起醉旦,我...
    開封第一講書人閱讀 37,006評論 0 259
  • 序言:老撾萬榮一對情侶失蹤饶米,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后车胡,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體檬输,經(jīng)...
    沈念sama閱讀 43,512評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,965評論 2 325
  • 正文 我和宋清朗相戀三年匈棘,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了丧慈。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,094評論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡主卫,死狀恐怖逃默,靈堂內(nèi)的尸體忽然破棺而出鹃愤,到底是詐尸還是另有隱情,我是刑警寧澤完域,帶...
    沈念sama閱讀 33,732評論 4 323
  • 正文 年R本政府宣布软吐,位于F島的核電站,受9級特大地震影響吟税,放射性物質(zhì)發(fā)生泄漏凹耙。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,283評論 3 307
  • 文/蒙蒙 一乌妙、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧建钥,春花似錦藤韵、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,286評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至镐依,卻和暖如春匹涮,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背槐壳。 一陣腳步聲響...
    開封第一講書人閱讀 31,512評論 1 262
  • 我被黑心中介騙來泰國打工然低, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人务唐。 一個(gè)月前我還...
    沈念sama閱讀 45,536評論 2 354
  • 正文 我出身青樓雳攘,卻偏偏與公主長得像,于是被迫代替她去往敵國和親枫笛。 傳聞我的和親對象是個(gè)殘疾皇子吨灭,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,828評論 2 345

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