IOS效能優化篇

slimsallen發表於2018-08-20

IOS效能優化篇
好的app應該有好的效能流暢度,本篇文章就大概講一下ios效能優化。

先來談談CPU和GPU

  • 在螢幕成像的過程中,CPU和GPU起著至關重要的作用
  • CPU( Central Processing Unit, 中央處理器)就是機器的“大腦”,也是佈局謀略、發號施令、控制行動的“總司令官”。
  • CPU的結構主要包括運算器(ALU, Arithmetic and Logic Unit)、控制單元(CU, Control Unit)、暫存器(Register)、快取記憶體器(Cache)和它們之間通 訊的資料、控制及狀態的匯流排。
  • GPU全稱為Graphics Processing Unit,中文為圖形處理器,就如它的名字一樣,GPU最初是用在個人電腦、工作站、遊戲機和一些移動裝置(如平板電腦、智慧手機等)上執行繪圖運算工作的微處理器。
  • 為什麼GPU特別擅長處理影象資料呢?這是因為影象上的每一個畫素點都有被處理的需要,而且每個畫素點處理的過程和方式都十分相似,也就成了GPU的天然溫床。

IOS效能優化篇
在iOS中是雙緩衝機制,有前幀快取、後幀快取,即GPU會預先渲染好一幀放入一個緩衝區內(前幀快取),讓視訊控制器讀取,當下一幀渲染好後,GPU會直接把視訊控制器的指標指向第二個緩衝器(後幀快取)。當你視訊控制器已經讀完一幀,準備讀下一幀的時候,GPU會等待顯示器的VSync訊號發出後,前幀快取和後幀快取會瞬間切換,後幀快取會變成新的前幀快取,同時舊的前幀快取會變成新的後幀快取。

螢幕成像原理

IOS效能優化篇

卡頓產生的原因

IOS效能優化篇
在Sync訊號到來後,系統圖形服務會通過CADisplayLink等機制通知App,App主執行緒開始在CPU中計算顯示內容,比如檢視的建立,佈局計算,圖片解碼,文字繪製等。隨後CPU會將計算好的內容提交到GPU去,由GPU進行交換,合成,渲染。隨後GPU會把渲染結果提交到幀緩衝區,等待下一次VSync訊號(垂直同步訊號)到來時顯示到螢幕上。由於垂直同步機制,如果在一個VSync時間內,CPU或者GPU沒有完成內容提交,則那一幀就會被丟棄,等待下一次機會再顯示,而這時螢幕因為沒有新的重新整理,會保留之前的內容不變。這就造成了卡頓。

  • 按照60FPS的刷幀率,每隔16ms就會有一次VSync訊號

卡頓優化 -CPU

  • 儘量用輕量級的物件,比如用不到事件處理的地方,可以考慮使用CALayer取代UIView
  • 不要頻繁地呼叫UIView的相關屬性,比如frame、bounds、transform等屬性,儘量減少不必要的修改
  • 儘量提前計算好佈局,在有需要時一次性調整對應的屬性,不要多次修改屬性
  • Autolayout會比直接設定frame消耗更多的CPU資源
  • 圖片的size最好剛好跟UIImageView的size保持一致
  • 控制一下執行緒的最大併發數量
  • 儘量把耗時的操作放到子執行緒

卡頓優化 -GPU

  • 儘量避免短時間內大量圖片的顯示,儘可能將多張圖片合成一張進行顯示
  • 儘量減少檢視數量和層次
  • 減少透明的檢視(alpha<1),不透明的就設定opaque為YES
  • 儘量避免出現離屏渲染

離屏渲染

  • 在OpenGL中,GPU有2種渲染方式
    1.On-Screen Rendering:當前螢幕渲染,在當前用於顯示的螢幕緩衝區進行渲染操作
    2.Off-Screen Rendering:離屏渲染,在當前螢幕緩衝區以外新開闢一個緩衝區進行渲染操作
  • 離屏渲染消耗效能的原因
    1.需要建立新的緩衝區
    2.離屏渲染的整個過程,需要多次切換上下文環境,先是從當前螢幕(On-Screen)切換到離屏(Off-Screen);等到離屏渲染結束以後,將離屏緩衝區的渲染結果顯示到螢幕上,又需要將上下文環境從離屏切換到當前螢幕
  • 哪些操作會觸發離屏渲染?
    1.光柵化,layer.shouldRasterize = YES
    2.遮罩,layer.mask
    3.圓角,同時設定layer.masksToBounds = YES、layer.cornerRadius大於0 考慮通過CoreGraphics繪製裁剪圓角,或者叫美工提供圓角圖片
    4.陰影,layer.shadowXXX 如果設定了layer.shadowPath就不會產生離屏渲染

耗電優化

耗電的主要來源?

IOS效能優化篇

  • CPU處理,Processing
  • 網路,Networking
  • 定位,Location
  • 影象,Graphics

1. 定位優化

  • 如果只是需要快速確定使用者位置,最好用CLLocationManager的requestLocation方法。定位完成後,會自動讓定位硬體斷電
  • 如果不是導航應用,儘量不要實時更新位置,定位完畢就關掉定位服務
  • 儘量降低定位精度,比如儘量不要使用精度最高的kCLLocationAccuracyBest
  • 需要後臺定位時,儘量設定pausesLocationUpdatesAutomatically為YES,如果使用者不太可能移動的時候系統會自動暫停位置更新
  • 儘量不要使用startMonitoringSignificantLocationChanges,優先考慮startMonitoringForRegion:

APP啟動優化

先來看app啟動流程

APP的啟動可以分為2種

1、冷啟動(Cold Launch):從零開始啟動APP
2、熱啟動(Warm Launch):APP已經在記憶體中,在後臺存活著,再次點選圖示啟動APP

APP啟動時間的優化,主要是針對冷啟動進行優化

  • 通過新增環境變數可以列印出APP的啟動時間分析(Edit scheme -> Run -> Arguments)
    1、DYLD_PRINT_STATISTICS設定為1
    2、如果需要更詳細的資訊,那就將DYLD_PRINT_STATISTICS_DETAILS設定為1

APP的冷啟動概括為三大階段

  • dyld,Apple的動態連結器,可以用來裝載Mach-O檔案(可執行檔案、動態庫等)
    啟動APP時,dyld所做的事情有
    1.裝載APP的可執行檔案,同時會遞迴載入所有依賴的動態庫
    2.當dyld把可執行檔案、動態庫都裝載完畢後,會通知Runtime進行下一步的處理

  • runtime 啟動APP時,runtime所做的事情有
    1.呼叫map_images進行可執行檔案內容的解析和處理
    2.在load_images中呼叫call_load_methods,呼叫所有Class和Category的+load方法
    3.進行各種objc結構的初始化(註冊Objc類 、初始化類物件等等)
    4.呼叫C++靜態初始化器和__attribute__((constructor))修飾的函式
    到此為止,可執行檔案和動態庫中所有的符號(Class,Protocol,Selector,IMP,…)都已經按格式成功載入到記憶體中,被runtime 所管理

  • main
    1.APP的啟動由dyld主導,將可執行檔案載入到記憶體,順便載入所有依賴的動態庫
    2.並由runtime負責載入成objc定義的結構
    3.所有初始化工作結束後,dyld就會呼叫main函式
    4.接下來就是UIApplicationMain函式,AppDelegate的application:didFinishLaunchingWithOptions:方法

IOS效能優化篇

優化方案

一、dyld

  • 減少動態庫、合併一些動態庫(定期清理不必要的動態庫)
  • 減少Objc類、分類的數量、減少Selector數量(定期清理不必要的類、分類)
  • 減少C++虛擬函式數量
  • Swift儘量使用struct

二、runtime

用+initialize方法和dispatch_once取代所有的__attribute__((constructor))、C++靜態構造器、ObjC的+load

三、main

  • 在不影響使用者體驗的前提下,儘可能將一些操作延遲,不要全部都放在finishLaunching方法中
  • 按需載入

後面會分享自己的優化過程

相關文章