iOS App性能優化

来源:http://www.cnblogs.com/shouce/archive/2016/03/31/5339807.html
-Advertisement-
Play Games

iOS App的性能關註點 雖然iPhone的機能越來越好,但是app的功能也越來越複雜,性能從來都是移動開發的核心關註點之一。我們說一個app性能好,不是簡單指感覺運行速度快,而應該是指應用啟動快速、UI反饋響應及時、列表滾動操作流暢、記憶體使用合理,當然更不能隨隨便便Crash啦。工程師開發應用時 ...


iOS App的性能關註點

雖然iPhone的機能越來越好,但是app的功能也越來越複雜,性能從來都是移動開發的核心關註點之一。我們說一個app性能好,不是簡單指感覺運行速度快,而應該是指應用啟動快速、UI反饋響應及時、列表滾動操作流暢、記憶體使用合理,當然更不能隨隨便便Crash啦。工程師開發應用時除了在設計上要避免性能“坑”的出現,在實際遇到“坑”時也要能很快定位原因所在。定位性能問題原因當然不能靠猜,合理的方法是使用工具測量評估出投資回報最高的問題點,然後再加以優化。

本文會從以下幾點介紹如何分析和優化iOS app的性能:啟動時間、用戶響應、記憶體、圖形動畫、文件和網路I/O。其中會用到Apple出品的性能分析神器“Instruments”。

啟動時間

應用啟動時間長短對用戶第一次體驗至關重要,同時系統對應用的啟動、恢復等狀態的運行時間也有嚴格的要求,在應用超時的情況下系統會直接關閉應用。以下是幾個常見場景下系統對app運行時間的要求: * Launch 20秒 Resume 10秒 Suspend 10秒 Quit 6秒 Background Task 10分鐘

要獲取準確的app啟動所需時間,最簡單的方法時首先在main.c中添加如下代碼:

1
2
3
CFAbsoluteTime StartTime;
int main(int argc, char **argv) {
  StartTime = CFAbsoluteTimeGetCurrent();

然後在AppDelegate的回調方法application:didFinishLaunchingWithOptions中添加:

dispatch_async(dispatch_get_main_queue(), ^{
    NSLog(@”Lauched in %f seconds.”,  (CFAbsoluteTimeGetCurrent() – StartTime)); 
});可能你會覺得為什麼這樣可拿到系統啟動的時間,因為這個dispatch_async中提交的工作會在app主線程啟動後的下一個run lopp中運行,此時app已經完成了載入並且將要顯示第一幀畫面,也就是系統會運行到`-[UIApplication _reportAppLaunchFinished]`之前。下圖是用Instruments工具Time Profiler跑的調用棧,Instruments的使用方法建議看WWDC中與performance相關的[session錄像](https://developer.apple.com/videos/wwdc),文字寫起來太單薄不夠直觀哈。

從圖中我們可以看到在系統調用[UIApplication _reportAppLaunchFinished]之前完成了系統回調application:didFinishLaunchingWithOptions

App的啟動會包括以下幾個部分(來自WWDC 2012 Session 235):

1)鏈接和載入:可以在Time Profile中顯示dyld載入庫函數,庫會被映射到地址空間,同時完成綁定以及靜態初始化。

2)UIKit初始化:如果應用的Root View Controller是由XIB實現的,也會在啟動時被初始化。

3)應用回調:調用UIApplicationDeleagte的回調:application:didFinishLaunchingWithOptions

4)第一次Core Animation調用:在啟動後的方法-[UIApplication _resportAppLaunchFinished]中調用CA::Transaction::commit實現第一幀畫面的繪製。如果你的程式啟動很慢,能 做的首先是將與顯示第一屏畫面無關的操作放到之後執行;如果是用XIB文件load第一屏,XIB文件中的View層也要如果扁平,不要有太多圖層。

用戶響應

如何能夠讓用戶覺得你的app響應迅速呢?當然是app用戶所觸發的操作都能得到立刻響應,即用戶事件(User Event)能夠被主線程的run loop及時處理。什麼是run loop?可以想象成一個處理事件的select多路復用。主線程中的run loop當然主要是為了處理用戶產生的事件啦,例如點擊、滾動等。以後我們會詳細聊聊run loop這個讓人迷惑的東東。

要讓主線程的run loop更好的響應用戶事件,工程師應該儘量減少主線程乾重活的時間,尤其是讀文件啊,網路操作啊,大量運算啊這類重活,如果是阻塞操作,那就更是大忌了。我們可以用多線程(NSThread、NSOperationQueue, GCD,下一篇Blog就會聊到這多線程)將重活移出主線程,這屬於顯式併發。還有種隱式併發,例如view和layer的動畫、layer的繪製以及PNG圖片的解碼都是在另一個子線程中執行的。除了使用多線程技術減輕主線程的負擔外,減少主線程中阻塞也是提升用戶體驗的一個方法。使用Instruments中Time Profiler工具中的”Recod thread waiting”選項可以統計出app運行時各個線程中的阻塞系統調用情況,例如文件讀寫read/write,網路讀寫send/recv,加鎖psynch_mutex_wait等。Instruments中的System Trace工具則能夠記錄所有的底層系統調用。

記憶體

記憶體問題從來都是iOS app的老大難問題,搞不好程式就爆了。由於iOS系統沒有Swap文件(知道為啥不?留給懸念),在記憶體不足時會將只讀數據(例如code page)從記憶體中移出,需要的時候再從disk上讀如記憶體;可讀寫數據不會被系統從記憶體中移出,然而如果占用的記憶體達到一個閾值,系統會發出相應的通知和回調讓應用release對象以回收記憶體,如果仍然不能減少記憶體使用量,系統會直接關閉應用。尤其是iOS 5.0之後,如果你的app收到了memory warning,那麼腦袋也是和其他app一樣放在了案板上,隨時有可能被kill掉,並不是說一定會先Kill掉在後臺的app。

App使用的記憶體除了我們在堆上分配的記憶體外(+[NSobject alloc]/malloc),還會有更多使用記憶體的地方,比如代碼和全局數據(TEXT和DATA),線程棧,圖片,view 的layer backing store等等。因此處理記憶體問題,絕不僅僅是我們開發app時儘量少申請記憶體那麼簡單。

現在有了超炫的ARC,記憶體問題相對少了很多,開發效率也得到了提高。但是很多公司的項目仍然由於歷史原因採用了手動管理記憶體,該做的活還是少不了。Xcode自帶的靜態分析功能可以幫你提前發現一些問題,然而有些記憶體問題是無法用靜態分析來發現的,例如我們不斷使用記憶體沒有及時釋放的問題,就無法使用靜態分析器分析出來。此時可以使用Instruments的Allocations和Leaks工具來檢查運行時的的記憶體使用以及泄露問題。

Allocations工具可以很直觀的反應app的記憶體使用情況,還有個很贊“Mark Heap”功能,在上圖左邊下半部分中的Heapshot Analysis中。例如你在進入一個頁面前點擊一下“Mark Heap”,然後再退回上一頁面點擊一下“Mark Heap”,如果你在進出這個頁面里所申請的記憶體都得到了合理的釋放,那麼堆的記憶體增長量就應該降至0(見上圖右下部分)。

另一種嚴重的記憶體使用問題是引用了已經釋放的記憶體,直接導致應用崩潰,而Allocation有一個選項Enable NSZombie detection能夠在應用使用已經釋放的記憶體時標註出來,同時顯示錯誤發生的調用棧信息。這為解決問題提供了最直接的幫助,當然缺點是必須能夠重現EXEC_BAD_ACCESS錯誤。

工具Leaks可以在應用運行時直接標示出存在記憶體泄露的代碼,如果發生了記憶體泄露,可以從泄露詳細信息中查看泄露的具體對象以及方法調用棧,大部分問題還是很好解決的。

圖形和動畫

圖形性能對用戶體驗有直接的影響,Instruments中的Core Animation工具用於測量物理機上的圖形性能,通過視圖的刷新頻率大小來判斷應用的圖形性能。例如一個複雜的列表滾動時它的刷新率應該努力趨近於60fps才能讓用戶覺得夠流暢,從這個數字也可以算出run loop最長的響應時間應該是16毫秒。

啟動Instruments的Core Animation工具後可以發現左下部分有一堆選項,我們來逐個介紹:

1) Color Blended Layers

Instruments可以在物理機上顯示出被混合的圖層Blended Layer(用紅色標註),Blended Layer是因為這些Layer是透明的(Transparent),系統在渲染這些view時需要將該view和下層view混合(Blend)後才能計算出該像素點的實際顏色,如果這種blended layer很多,那麼在滾動列表時就甭想有流暢的效果。

解決blended layer問題也很簡單,檢查紅色區域view的opaque屬性,記得設置成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],系統會將這些Layer緩存成Bitmap點陣圖供渲染使用,如果失效時便丟棄這些Bitmap重新生成。圖層Rasterization柵格化好處是對刷新率影響較小,壞處是刪格化處理後的Bitmap緩存需要占用記憶體,而且當圖層需要縮放時,要對刪格化後的Bitmap做額外計算。 使用這個選項後時,如果Rasterized的Layer失效,便會標註為紅色,如果有效標註為綠色。當測試的應用頻繁閃現出紅色標註圖層時,表明對圖層做的Rasterization作用不大。

3) Color Misaligned Images

Misaligned Image表示要繪製的點無法直接映射到頻幕上的像素點,此時系統需要對相鄰的像素點做anti-aliasing反鋸齒計算,增加了圖形負擔,通常這種問題出在對某些View的Frame重新計算和設置時產生的。

上圖中被標註為黃色的圖層,這是由於圖層顯示的是被縮放後的圖片,如果這些圖片是通過網路下載的,可以通過程式更新為確定的繪製大小來解決。還有些系統Navigation Bar和Tool Bar的背景圖片使用的是拉伸(Streched)圖片,也會被表示為黃色,這是屬於正常情況,通常無需修改。這種問題一般對性能影響不大,而是可能會在邊緣處虛化。

(4) Color Offscreen-Rendered Yellow

Offscreen-Rendering離屏渲染意思是iOS要顯示一個視圖時,需要先在後臺用CPU計算出視圖的Bitmap,再交給GPU做Onscreen-Rendering顯示在屏幕上,因為顯示一個視圖需要兩次計算,所以這種Offscreen-Rendering會導致app的圖形性能下降。

大部分Offscreen-Rendering都是和視圖Layer的Shadow和Mask相關,下列情況會導致視圖的Offscreen-Rendering: 1. 使用Core Graphics (CG開頭的類)。 2. 使用drawRect()方法,即使為空。 3. 將CALayer的屬性shouldRasterize設置為YES。 4. 使用了CALayer的setMasksToBounds(masks)和setShadow*(shadow)方法。 5. 在屏幕上直接顯示文字,包括Core Text。 6. 設置UIViewGroupOpacity。

這篇博文Designing for iOS: Graphics & Performance對offsreen以及圖形性能有個很棒的介紹,(5) Color Copied Images Copied Image選項可以標註應用繪製時被Core Animation複製的圖片,標註成藍綠色。雖然我在運行時遇到過,不過個人感覺對圖形性能影響不大。 (6) Color Immediately,Flash Updated Regions, Color OpenGL Fast Path Blue Color Immediately選項表示Instruments在做color-flush操作時取消10毫秒的延時。Flash Updated Regions選項用於用紅色示標示出在屏幕上使用GPU計算繪製的圖層。Color OpenGL Fast Path Blue選項用於用藍色標示出在屏幕上由OpenGL compositor繪製的內容。 這三個選項對圖形性能的分析意義較小,通常僅作為參考。

文件和網路I/O

如果需要對app的文件和網路I/O情況做分析,可以用到這三個Instruments工具System Usage、File Activity和Network。

工具System Usage可以統計出運行狀態下應用的文件和網路IO操作數據。例如我們發現應用啟動後又一個峰值,這可能存在問題,我們可以利用System Usage工具的詳細信息欄查看應用是由於對哪些文件的讀寫操作導致了峰值。

工具File Activity只能在模擬器中運行,因此數據採集可能不是非常準確。它同樣可以詳細給出讀取的文件屬性、大小、載入時間等信息,適合與System Usage配合使用。

Network工具則可以採集到應用的TCP/IP和UDP的使用信息(傳輸的數據量、當前所有TCP連接等),用得不多,做網路使用狀況分析時用用還行。

更多閱讀

涉及iOS App性能的知識很多,上面只是冰山一角,重點推薦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

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 在iOS 8.0以上版本中, 我們可以使用UISearchController來非常方便地在UITableView中添加搜索框. 而在之前版本中, 我們還是必須使用UISearchBar + UISearchDisplayController的組合方式. 添加UISearchController屬性 ...
  • swift 版 iOS 飯否客戶端 源碼下載:http://code.662p.com/view/13318.html 飯否是中國大陸地區第一家提供微博服務的網站,被稱為中國版Twitter。用戶可通過網頁、WAP、手機簡訊/彩信、IM 軟體(包括 QQ、MSN、GTalk)和上百種API 應用在自 ...
  • 這是國內目前第一款集合了AR實景,3D游戲和人臉識別的射擊游戲,通過旋轉和改變手機的角度與位置,所有的射擊操作都靠手勢來完成,目前所有的源碼全部都在這裡。appStore地址:https://itunes.apple.com/us/app/sky-fighting/id1070732279?l=zh ...
  • 一,代碼。 二,輸出。 ...
  • There was an internal API error. 錯誤原因:把Product Name作為程式名稱,程式名稱錯亂 解決方法:檢查Product Name, 不要包含中文以及特殊字元。在info.plist中新增Bundle display name:我的程式名稱。程式名稱改為英文,P ...
  • 項目使用RxJava+Retrofit2.0+MVP 後臺查詢使用LeanCloud REST API 主要實現了商品列表的獲取(載入更多和刷新)與展示,根據商品種類查詢 源碼下載:http://code.662p.com/view/13294.html 詳細說明:http://android.66 ...
  • 通過使用該源碼,開發者可以迅速地將Discuz論壇遷移到Android客戶端中。不需要任何的開發工作即可擁有屬於自己論壇的Android客戶端 源碼下載:http://code.662p.com/view/13266.html 準備工作 在使用源碼之前必須先在Discuz論壇中安裝BigApp插件。 ...
  • Android 開發了一段時間,一方面 ,感覺不留下點什麼。有點對不起自己, 另一方面,好記性不如爛筆頭,為了往後可以回頭來看看,就當做是筆記,便決定開始寫博客。廢話不多說 ! 今天想搞一搞 ndk 和jni ,, 現在開始寫一個簡單的demo 1. 創建一個新的工程 2. 創建一個新的類 JniT ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...