性能優化-詳解web
性能測試:實時監測應用內存、CPU消耗緩存
部分性能指標及定義性能優化
性能指標 指標描述網絡
應用首次啓動時間 測量系統從開始處理 activity到完成運行進入主界面的時間,即冷啓動響應時間多線程
界面幀率 FPS指應用每秒渲染幀數,是用戶對應用界面所量現的畫面流暢度的體驗,FPS太低,用戶可感知的流暢度差。 併發
應用前臺運行內存佔用 應用在前臺且運行穩定時的內存佔用狀況app
應用後臺運行CPU佔用 應用在後臺且亮屏時的cPU佔用狀況。函數
CPU&GPU理解工具
CPU:中央處理器(Central Processing Unit)佈局
GPU:圖形處理器(Grphics Processing Unit)
屏幕成像原理:
屏幕的顯示成像是結合CPU數據處理和GPU渲染而來的,即每次屏幕刷新時都會受到CPU和GPU的影響。CPU計算顯示內容(視圖的建立、佈局計算、圖片解碼、文本繪製等),完成後將計算好的內容提交到GPU,由GPU進行變換、合成、渲染,隨後GPU會把渲染結構提交的幀緩衝區去,等待下一此垂直同步信號到來時顯示到屏幕上。iOS系統圖形服務提供CADisplayLink等機制通知App,App在主線程開始上述操做。若是在一個刷新時間內,CPU或GPU沒有完成內容提交,則那一幀就會被丟棄,等待下一次機會再顯示,而此時顯示屏會保持以前的內容不變,從而產生掉幀狀況,從而致使界面卡頓。
離屏渲染
在OpenGL中,GPU有兩種渲染方式
①On-Screen Rendering : 當前屏幕渲染,在當前用於顯示的屏幕緩衝區進行渲染操做.
②Off-Screen Rendering : 離屏渲染 ,在當前屏幕緩衝區之外新開闢一個緩衝區進行渲染操做.
離屏渲染消耗性能的緣由
1.須要建立新的緩衝區
2.離屏渲染的整個過程,須要屢次切換上下文環境,先是從當前屏幕(On-Screen)切換到離屏(Off-Screen);
當離屏渲染結束之後,將離屏緩衝區的渲染結果顯示到屏幕上,又須要將上下文環境從離屏切換到當前屏幕。
哪些操做會觸發離屏渲染?
1.光柵化, layer.shouldRasterize = YES.
(rasterizedLayer柵格化的空間是有限的,iOS大概有屏幕大小兩倍的空間來存儲rasterizedLayer或是屏幕外緩衝區)若是設置了shouldRasterize=YES,也要設置rasterizationScale 爲 contentsScale.即
self.layer.shoudlRasterize = YES;
self.layer.rasteriztionScale = [UIScreen mainScreen].scale;
2.遮罩, layer.mask
3.圓角, 同時設置layer.masksToBounds = YES、layer.cornerRadious 大於0(經過CoreGraphics繪製裁剪圓角,或者美工提供圓角圖片)
4.陰影, layer.shadowXX (若是設置了layer.shadowPath就不會產生離屏渲染)
5.系統的切圓角也會觸發離屏渲染
view.layer.cornerRadious = 5; view.layer.maskToBounds = true;
①卡頓優化-CPU
1.儘可能用輕量級的對象,好比,用不到事件處理的地方,能夠考慮用CALayer代替UIView.
2.不要頻繁調用UIView的相關屬性,好比frame、bounds、transform等屬性,儘可能減小沒必要要的修改.
3.儘可能提早計算好佈局,在有須要時一次性調整對應的屬性,不要屢次修改屬性。
4.AutoLayout要比直接修改frame消耗更多的CPU資源。
5.圖片的size最好和UIImageView的size保持一致
6.控制一下線程的最大併發數量
7.儘可能把耗時的操做放在子線程
②卡頓優化-GPU
1.儘可能避免短期內大量圖片的顯示,儘量將多張圖片合成一張進行顯示
2.儘可能減小視圖數量和層次
3.減小透明的視圖(alpha<1),不透明的就設置opaque爲YES.
4.儘可能避免出現離屏渲染
其餘:
A.頻繁操做部分界面
B.自定義繪圖渲染(代碼)
C.App啓動(冷啓動、熱啓動)
D.選擇API 多線程/UIImageAPI
E.文件讀寫
F.APP太大了(如何給APP瘦身)?
G.內存使用不正確
③耗電優化
耗電的主要來源:
④定位優化:
⑤App啓動優化
App啓動方式:
1.冷啓動:(Cold Launch): 從零開始啓動App
2.熱啓動(Warm Launch) App 已經在內存中,在後臺存活着,再次點擊圖標啓動APP
App啓動時間的優化主要針對冷啓動進行優化
經過添加環境變量能夠打印出來App的啓動時間分析(Edit scheme - >Run ->Arguments)
1.DYLD_PRINT_STRATISTICS設置爲1
2.若是須要更詳細的信息,那就將DYLD_PRINT_STRATISTICS_DETAILS設置爲1
App冷啓動大體分三個階段
①dyld , Apple的動態連接器,能夠用來裝在Mach-O文件(可執行文件、動態庫)
啓動App時,dyld作的事
1.裝載App的可執行文件,同時會遞歸加載全部依賴的動態庫
2.當dyld把可執行文件、動態庫都裝載完畢後,會通知Runtime進行下一步的處理
②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.並由runtiem負責加載成objc定義的結構。
3.全部初始化工做結束後,dyld就會調用main函數
4.接下來就是UIApplicationMain函數,AppDelegate的application:didFinishLaunchingWithOptions:方法
優化方案
1、dyld
減小動態庫、合併一些動態庫(按期清理沒必要要的動態庫)
減小Objc類、分類的數量、減小Selector的數量(按期清理沒必要要的類,分類)
減小C++虛函數數量
Swift儘可能使用Struct
2、runtime
用+initialize方法和dispatch_once取代全部的__attribute__((constructor))、C++靜態構造器、ObjC的+load方法
3、main
在不影響用戶體驗的前提下,儘量將一些操做延遲,不要所有都放在finishLaunching方法中,按需加載。
⑥圓角終極優化方案
/* 實際中重繪圓角的優化方案須要考慮的是,將圖像從新繪製爲爲圓角圖像至關於多了一份拷貝,要不要緩存?A.第一次重繪後將這些圓角圖像緩存在磁盤裏,第二次加載直接使用緩存的圓角圖像;B.直接保存在內存裏,在內存比較吃緊時顯然不是個好選擇;C.不緩存,和系統圓角同樣,每次都重繪,浪費電量。 */ // 終極優化方案: /* //Ultimate Solution: Rasterization Typical use cases: Avoid redrawing expensive effects for static content Avoid redrawing of complex view hierarchies */ func enableRasterizationOn(_ view: UIView) { view.layer.shouldRasterize = true view.layer.rasterizationScale = view.layer.contentsScale }
總結
1.RoundedCorner 在僅指定cornerRadius時不會觸發離屏渲染,僅適用於特殊狀況:contents爲 nil 或者contents不會遮擋背景色圓角;
2.Shawdow 能夠經過指定路徑來取消離屏渲染;
3. Mask 沒法取消離屏渲染;
以上效果在同等數量的規模下,對性能的影響等級:Shadow > RoundedCorner > Mask > GroupOpacity(迷之效果)。
任什麼時候候優先考慮避免觸發離屏渲染,沒法避免時優化方案有兩種:
1. Rasterization:適用於靜態內容的視圖,也就是內部結構和內容不發生變化的視圖,對上面的全部效果而言,在實現成本以及性能上最均衡的。即便是動態變化的視圖,開啓 Rasterization 後可以有效下降 GPU 的負荷,不過在動態視圖裏是否啓用仍是看 Instruments 的數據。
2. 規避離屏渲染,用其餘手法來模擬效果,混合圖層是個性能最好、耗能最少的通用優化方案,尤爲對於 rounded corer 和 mask。
⑦穩定App緩存
scrollViewDidScrollView,清除緩存
// 清除緩存 [[SDImageCache sharedImageCache] clearMemory]; // 設置緩存時長爲1個月 // [SDImageCache sharedImageCache].maxCacheAge = 30 * 24 * 60 * 60; // 清除沙盒中全部使用SD緩存的過時圖片(緩存時長 > 一個星期) // [[SDImageCache sharedImageCache] cleanDisk]; // 清除沙盒中全部使用SD緩存的圖片 // [[SDImageCache sharedImageCache] clearDisk];
⑧UITableView-hightForRow調用時機+Cell行高計算(緩存)
⑨內存優化分析 如何檢測內存方面的問題
公共配置:
A:打開全局斷點, 殭屍對象檢測,Zombie Objects 進行野指針的檢測
[Person release]: message sent to deallocated instance 0x60400001e690
B:打開全局斷點
C.(dealloc方法)析構方法打印看調沒調用
常見問題彙總:
循環引用 / 錯誤的內存訪問 / 內存消耗<RAM :運行內存 ROM:SD卡>
內存泄漏 / 內存溢出
Exc_BAD_ACESS野指針(錯誤的內存訪問 )
/* (a 向一個已經釋放的對象發送消息) (b weak) (c 指針) 檢測方法: 打開殭屍斷點 Edit Scheme-> Run->Diagnostics->Memory Management ->Malloc Scribble (Bugly 函數 )(增大野指針的崩潰率) -> Zombie Objects 殭屍對象 */
1.需求分析:UIViewController是否釋放,pop/push
2.思路分析:
①ViewWillAppear / DidDisAppear
②肯定對象是否存活
1.靜態檢測方法
手動:選中Xcode -> Product -> Analyze 【Shift +Command + B】
自動檢測:Build-settings 搜索 Analyze
Analyze During ‘Build’ 設置爲YES
2.動態檢測方法 Instruments->Leaks
1.跟蹤收集信息
2.分析信息,定位問題
3.定位問題,解決問題
分析在繪製過程當中捕獲的數據。修復源代碼中的任何問題
建議:Instruments 每次修改代碼切記使用 cmd + I 進行profile記錄
內存泄漏檢查 常見的內存問題(內存泄露、野指針、殭屍對象、循環引用)
Xcode - > Open Developer Tool -> Instruments -Leaks
循環引用:精確到類名
Leaks -> Cycles & Roots >Leak Cycles
3.第三方檢測工具
pod ‘MLeaksFinder’, ‘~> 1.0.0’
思路:
/* UIViewController 延遲發送消息 push ->viewWillAppear: NO pop -> YES viewDidDisappear: 標識信息,發送消息 */