來自:slimsallen
鏈接:https://juejin.im/post/5b7a9c466fb9a019eb43b0d5
好的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中是雙緩衝機制,有前幀快取、後幀快取,即GPU會預先渲染好一幀放入一個緩衝區內(前幀快取),讓視頻控制器讀取,當下一幀渲染好後,GPU會直接把視頻控制器的指標指向第二個緩衝器(後幀快取)。當你視頻控制器已經讀完一幀,準備讀下一幀的時候,GPU會等待顯示器的VSync信號發出後,前幀快取和後幀快取會瞬間切換,後幀快取會變成新的前幀快取,同時舊的前幀快取會變成新的後幀快取。
屏幕成像原理
卡頓產生的原因
在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就不會產生離屏渲染
耗電優化
耗電的主要來源?
-
CPU處理,Processing
-
網絡,Networking
-
定位,Location
-
圖像,Graphics
定位優化
-
如果只是需要快速確定用戶位置,最好用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:方法
優化方案
一、dyld
-
減少動態庫、合併一些動態庫(定期清理不必要的動態庫)
-
減少Objc類、分類的數量、減少Selector數量(定期清理不必要的類、分類)
-
減少C++虛函式數量
-
Swift儘量使用struct
二、runtime
用+initialize方法和dispatch_once取代所有的__attribute__((constructor))、C++靜態建構式、ObjC的+load
三、main
-
在不影響用戶體驗的前提下,盡可能將一些操作延遲,不要全部都放在finishLaunching方法中
-
按需加載
後面會分享自己的優化過程
Follow:https://github.com/sallenhandong
Source:https://slimsallen.com/#/detail/iosperformance.md
●編號287,輸入編號直達本文
●輸入m獲取文章目錄
Web開發
更多推薦《18個技術類微信公眾號》
涵蓋:程式人生、演算法與資料結構、黑客技術與網絡安全、大資料技術、前端開發、Java、Python、Web開發、安卓開發、iOS開發、C/C++、.NET、Linux、資料庫、運維等。