商業轉載請聯繫騰訊WeTest得到受權,非商業轉載請註明出處。緩存
WeTest 導讀安全
空間新業務需求日益增多,在業務開發階段的疏忽,或者是受到其餘業務的影響(好比一些非空間的業務網絡回包或者邏輯在主線程進行),致使空間的某些頁面掉幀率上升。微信
本文從兩個方向介紹優化掉幀率:網絡
● Time Profiler時間分析工具多線程
● 一些優化手段app
Time Profiler(Xcode 9.1)異步
Time Profiler分析原理:它按照固定的時間間隔來跟蹤每個線程的堆棧信息,經過統計比較時間間隔之間的堆棧狀態,來推算某個方法執行了多久,並得到一個近似值。
下面是Time Profiler的界面說明和一些使用建議。ide
一、主線程使用波峯函數
開始模擬用戶使用App的時候,能夠看到主線程的使用狀況,它的波峯會忽高忽低,說明app正在進行耗時計算/正常計算,咱們能夠截取不一樣時間段的波峯區間進行探究,好比剛進入空間的5秒內,或者拉取到新feeds流以後平緩的5秒等不一樣場景(小tips:使用觸控板向左右兩邊挪動能夠進一步細化時間區間)工具
二、關於篩選面板的使用
● Separate by State:此選項會根據應用程序的生命週期狀態對結果進行分組,而且是檢查應用程序在多大程度上執行以及什麼時候執行的有用方法。
● Separate by Thread:根據線程類別分開,方便查看哪些線程佔用了最大的CPU。
● Invert Call Tree:調用樹倒返過來,將習慣性的從根向下一級一級的顯示,如選上就會返過來從最底層調用向一級一級的顯示。若是想要查看那個方法調用爲最深時使用會更方便些。
● Hide System Libraries:選上它只會展現與應用有關的符號信息,通常狀況下咱們只關心本身寫的代碼所需的耗時,而不關心繫統庫的CPU耗時。(可是不少咱們的代碼每每是由系統的函數進來,隱藏的話每每可能會丟失很重要的信息)
● Flatten Recursion:將遞歸函數視爲每一個堆棧跟蹤中的一個條目,而不是多個。
● Top Functions:將花費在函數中的總時間視爲直接在該函數內的時間總和以及該函數所調用的函數花費的時間。若是函數A調用B,那麼A的時間被報告爲A的時間而且加上在B中花費的時間。
爲了能夠獲取更多的信息,建議只勾選 「Separate by Thread」
三、操做小技巧
在摺疊的堆棧,按住「alt」點開旁邊的三角形便可展開所有摺疊堆棧,若是發現耗時嚴重的堆棧中,能夠右鍵點開菜單,選中「Reveal in Xcodes」便可跳轉到對應的代碼區域 。
實戰應用
在好友動態頁面來回滑動,筆者分四種狀況來模擬用戶的使用習慣:
● 剛進入空間(無緩存),下拉刷新
● 剛進入空間(有緩存),下拉刷新
● 來回滑動
● 上拉加載更多
一、將耗時操做(如文件IO)放到工做線程
在咱們讀取Gif首幀的時候,-[QZoneGIFDecode firstFrameWithURL:viewSize:]裏面是有一部是從磁盤裏讀取二進制文件而且轉換成NSData,而後再進行解碼,這部分的IO操做優化後是放到了工做線程,異步讀取完成解碼以後再展現圖片,不阻塞主線程。
再舉一個例子:異步解析網絡回包數據和異步排版
將耗時操做放到工做線程異步執行佔了優化工做的大頭,在這個過程當中,要注意多線程問題,好比線程安全問題、死鎖、野指針等,好比容器類的讀寫操做,最經常使用的NSMutableArray, NSMutableDictionary等, 這類集合在調用讀寫方法時並非線程安全,簡單地在裏面進行加鎖操做是能夠保證線程安全,不過也可能會致使其餘耗時問題。
二、耗時函數優化
上圖堆棧表示的是展現圖片, 整個流程以下:
因爲空間裏面存在大部分圖片,其中走網絡下載的圖片就是上述這個流程。在這個過程當中,刨開網絡下載的部分,咱們會根據圖片URL來存取。存取過程首先會將URL 進行MD5加密以後做爲Key來進行存取,其實這一步不是必要的,並且系統提供的MD5函數比較耗時。
優化手段:
優化緩衝池存取過程,直接使用URL做爲Key來存取,去掉MD5調用。
三、減小- (void)scrollViewDidScroll(UIScrollView *)scrollView 這個函數裏面的耗時操做:
這個方法在任何方式觸發 contentOffset 變化的時候都會被調用(包括用戶拖動,減速過程,直接經過代碼設置等),能夠用於監控 contentOffset 的變化,並根據當前的 contentOffset 對其餘 view 作出隨動調整。可是這個方法在滾動的時候每秒調用上百次,若是在裏面加入耗時操做就可能對掉幀率形成很大影響。
解決方法:優化調用耗時,或者將耗時操做放到別的地方去
四、提早進行(耗時操做不可避免)
在進入空間以前,咱們會有不少初始化工做,好比初始化用戶的空間裝扮,讀取用戶的一些配置等,有時候還會涉及IO操做,這部分的耗時是必不可免的。爲了保證用戶的體驗問題,進入空間前,咱們能夠提早初始化(preload),將一些耗時操做選擇在適當的時機提早進行。
五、緩存
在業務上,咱們會讀取一些設置項來展現或者進行不一樣的功能,這些選項的即時讀取多是很是耗時的(尤爲是涉及非線程安全容器的讀取,裏面每每是利用了互斥鎖或者信號量等機制保證線程安全,耗時就更加嚴重),咱們可使用靜態變量和dispatch_once來保存起來,避免每次都去要讀取一遍。
再舉一個例子:
咱們在渲染的時候會用到不少字體顏色,每次建立這些新的字體和顏色也是耗時的一部分,咱們能夠將這些UIColor和UIFont緩存起來,過程以下圖:
這裏還能夠作進一步的優化,就是在進入空間前,把經常使用的字體生成而且緩存起來,減小渲染時再生成的耗時。
六、減小沒必要要的操做
爲了方便回溯用戶的操做行爲,咱們會在App裏面加上不少log,通常log都涉及IO操做,不是必要的log咱們要減小,儘可能只在關鍵點打log。
七、懶加載view
不要在cell裏面嵌套太多的view,這會很影響滑動的流暢感,並且更多的view也須要花費更多的CPU跟內存。假如因爲view太多而致使了滑動不流暢,那就不要在一次就把全部的view都建立出來,把部分view放到須要顯示cell的時候再去建立。好比:
八、利用主線程不一樣的runloop
優化緩衝池存取過程,直接使用URL做爲Key來存取,去掉MD5調用。
上圖是進入空間的時候,須要初始化混合Cover掛件的耗時問題。
咱們能夠利用不一樣的runloop來優化這個耗時問題。主線程的 RunLoop 裏有兩個預置的 Mode:kCFRunLoopDefaultMode 和 UITrackingRunLoopMode。這兩個 Mode 都已經被標記爲"Common"屬性。DefaultMode 是 App 平時所處的狀態,TrackingRunLoopMode 是追蹤 ScrollView 滑動時的狀態。當咱們初始化掛件並加到 DefaultMode 時,這個事件 會獲得重複回調,但此時滑動一個TableView時,RunLoop 會將 mode 切換爲 TrackingRunLoopMode,這時 初始化掛件函數就不會被回調,於是也不會影響到滑動操做。
不少App會用到這個點來進行優化,好比咱們操做微信的時候,在朋友圈上拉加載更多的時候,若是不鬆開手是不會加載出來的,只有放開手纔會展現出更多的feeds,也是利用了不一樣的runloop。
解決掉幀的方法還有不少,但願本文能提供給你們一些思路,後續會繼續更新。
UPA—— 一款針對Unity遊戲/產品的深度性能分析工具,由騰訊WeTest和unity官方共同研發打造,能夠幫助遊戲開發者快速定位性能問題。旨在爲遊戲開發者提供更完善的手遊性能解決方案,同時與開發環節造成閉環,保障遊戲品質。
目前,限時內測正在開放中,即日起至2017.12.21,全部預定成功的WeTest平臺認證用戶,都可以避免費、不限次數地使用最完整的UPA服務,點擊http://wetest.qq.com/cube/ 當即預定。
對UPA感興趣的開發者,歡迎加入QQ羣:633065352
若是對使用當中有任何疑問,歡迎聯繫騰訊WeTest企業QQ:800024531