天天看點

iOS界面卡頓分析和優化:Instrument 調試界面卡頓(更新:離屏渲染)

更新:2019年7月10号

卡頓分析方案:

 1、根據主線程Runloop的狀态(kCFRunLoopBeforeSources和kCFRunLoopAfterWaiting,即正在處理任務的狀态),做實時監控主線程卡頓。(可以參考:iOS實時卡頓監控)

 2、監控FPS,要保持流暢的UI互動,App 重新整理率應該努力保持在 60fps。(可以參考:微信讀書團隊GYMonitor工具)

更新:2018年4月20号

關于離屏渲染的詳細介紹:iOS"離屏渲染"整理總結

離屏渲染優化詳解:離屏渲染優化詳解:執行個體示範+性能測試

圓角性能問題解決辦法:設定圓角引發性能問題的解決辦法

前言

工欲善其事,必先利其器。Instrument對于iOS開發來說,是發現并且解決問題的一把利器。

本文會用到的兩個工具包括:

  • Time Profiler(擷取代碼運作時間,一般用來看CPU占用)
  • Core Animation(擷取圖形繪制情況,FPS,離屏渲染等)

界面顯示的原理

iOS裝置通常是60fps(每秒60幀),也就是說兩幀相隔的時間是1/60秒,大概16.7ms。在這16.7ms中,為了顯示一幀,需要如下工作

  • CPU計算好各個視圖的位置,大小,對圖檔進行解碼等,繪制成紋理交給GPU
  • GPU對收到的紋理進行混合,頂點變換,渲染到幀緩沖區
  • 每16.7ms,一個時鐘信号到達,幀緩沖區取出一幀,顯示到螢幕。

也就是說,CPU或者GPU被大量占用的時候,都有可能在16.7ms中沒辦法完成一幀的繪制,導緻時鐘信号到來的時候,取得還是上一幀的内容,也就都有可能導緻界面卡頓

離屏渲染

在iOS中,渲染通常分為CPU和GPU渲染兩種,而GPU渲染又分為在GPU緩沖區和非GPU緩沖區兩種

  • CPU渲染(軟體渲染),CPU繪制成bitmap,交給GPU
  • GPU渲染(硬體渲染) 
    • GPU緩沖區渲染
    • 非GPU緩沖區渲染(額外開辟緩沖區)

通常,CPU渲染,和GPU非幀緩沖區内渲染統稱為離屏渲染。因為,CPU和幀緩沖區是為圖形圖像顯示做了高度優化的,速度較快。

什麼情況下會觸發離螢幕渲染?

  • 用CoreGraphics的CGContext繪制的
  • drawRect

    中繪制的,即使

    drawRect

    是空的
  • Layer具有

    Mask

    (比如圓角)或者

    Shadow

  • Layer的隔栅化

    shouldRasterize為True

  • 文本(UILabel,UITextfield,UITextView,CoreText,UITextLayer等)

離屏渲染一定會引起性能問題嗎?

很少會,比如

drawRect

這個方法,隻會在時圖進行重新繪制的時候才會調用。也就是說,假如你的View并不會頻繁重繪,那麼即使實作了

drawRect

,也沒什麼關系。

對了,目前iOS裝置的硬體越來越好也是一個原因,想要要性能差也挺難的。

CoreGraphics VS CALayer

上文提到了,CoreGraphics通常是CPU渲染成bitmap交給GPU,假如頻繁的大量的繪制出現,往往會導緻界面卡頓。而CALayer是對GPU做過優化的,能夠硬體加速。是以,對于性能要求較高的繪制,嘗試用CALayer替代CoreGraphics

一個反面教材

一定要在真機上測試性能才有意義,本文是采用iPhone 5s來調試的。一般測試性能支援的性能最差的就可以了,如果是iOS 8要測試4s上的性能。

界面很簡單,一個ImageView,右側是随機生成的100個字元,富文本顯示。

iOS界面卡頓分析和優化:Instrument 調試界面卡頓(更新:離屏渲染)

Time Profile

1.打開Time Profile,然後運作想要分析的App

iOS界面卡頓分析和優化:Instrument 調試界面卡頓(更新:離屏渲染)

2.進入主界面,上下滾動List,讓Time Profile采集資料, 

勾選右側的

  • Separate by Thread,按線程區分
  • Invert Call Tree ,逆向Call Tree,友善我們檢視方法調用順序
  • Hide System Libraries,隐藏系統的庫,因為通常系統的代碼并不會影響性能
iOS界面卡頓分析和優化:Instrument 調試界面卡頓(更新:離屏渲染)

3.可以選擇一段時間,來分析這段時間CPU的使用情況 

iOS界面卡頓分析和優化:Instrument 調試界面卡頓(更新:離屏渲染)

4.找到占用時間最多的代碼

iOS界面卡頓分析和優化:Instrument 調試界面卡頓(更新:離屏渲染)

然後,輕按兩下占用最多的這一行,進入實際的代碼,看看到底哪裡占用比較多

iOS界面卡頓分析和優化:Instrument 調試界面卡頓(更新:離屏渲染)

這裡,我們看到是這一行代碼

cell.testLabel?.attributedText = mutableAttr

。 

占用最多的CPU時間。

我們先來看下整個方法代碼,

  • TableViewCell

    其實很簡單,就一個

    ImageView

    (帶圓角,陰影),一個

    UILabel

  • cellForRowAtIndexPath

    裡會随機的生成100個字元,然後用

    AttributeText

    來讓

    UILabel

    顯示

乍一看,問題應該是這個随機生成100個字元的函數啊

func calculateRandomText()->String{
        var result = ""
        for _ in 0...100{
            let random = getRandomCharFromString(globalStr)
            result.appendContentsOf(random)
        }
        return result
    }
           
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

因為,每一次CellForRow調用的時候,都會計算100次。然後,我們實際分析的時候,發現其實100次對顯示來說,真不算什麼,也不是卡頓的原因。

那麼,為什麼設定

attributeText

占用時間這麼多呢?

其實很簡單,

attributeText

是建立在TextKit上的,由于每一次顯示都是随機的

attributeText

,每一次都要重新計算文本的大小,位置等等。另外,UIKit中,提供的文本渲染都是在CPU中進行的,渲染成Bitmap,然後交給GPU,是以導緻設定attributeText的時候,占用很多時間。

這裡不得不提到:一定不要過早優化,優化的時候盡量依賴于Instrument的分析結果,而不是自己的主觀感受。尤其當你還是個新司機的時候。

Core Animation

在Instrument中,Command+L打開Library,然後添加Core Animation。我們來看看GPU的相關的問題

最直覺的就是滾動視圖,檢視FPS(Frame per second),一般小于50幀就會看到明顯的掉幀。

備注:這裡的很多參考自這本書

1.看看圖層混合情況

  • 隻開啟

    Color Blended Layers

    ,然後沒有混合的部分會是綠色,混合最嚴重的部分會是紅色。大量的圖層混合會消耗GPU的時間,因為對于一個像素點,GPU不能簡單的使用最上層的視圖的顔色,而是需要進行計算疊加。

會看到截圖如下 

iOS界面卡頓分析和優化:Instrument 調試界面卡頓(更新:離屏渲染)

這裡的Cell整個背景都是紅的,因為背景是

alpha

為0.3的View,

UILabel

是深紅色的,因為大量的陰影。

2.看看隔栅化情況,

  • 隻開啟

    Color Hits Green and Misses Red

    ,當使用shouldRasterize屬性的時候,耗時的圖層繪制會被緩存,然後當做一個簡單的扁平圖檔呈現。當緩存無法使用必須重建的時候,會被高亮為紅色。

截圖如下:

iOS界面卡頓分析和優化:Instrument 調試界面卡頓(更新:離屏渲染)

3.看看拷貝圖檔情況

  • 隻開啟

    Color Copied Images

     - 有時候寄宿圖檔的生成意味着Core Animation被強制生成一些圖檔,然後發送到渲染伺服器,而不是簡單的指向原始指針。這個選項把這些圖檔渲染成藍色。複制圖檔對記憶體和CPU使用來說都是一項非常昂貴的操作,是以應該盡可能的避免。

我的測試項目裡沒有這個,是以不貼圖了。

4.看看圖檔有沒有像素不對齊,有沒有拉伸和縮放

  • Color Misaligned Images

    ,可以看到如下。(因為我們的縮略圖其實是一張很大的圖,是以被縮放了,導緻顯示成黃色)

5.看看離屏渲染

-隻開啟

Color Offscreen-Rendered Yellow

,離螢幕渲染的部分會被高亮成黃色

iOS界面卡頓分析和優化:Instrument 調試界面卡頓(更新:離屏渲染)

6.其他選項

  • Color Immediately 通常Core Animation Instruments以每毫秒10次的頻率更新圖層調試顔色。對某些效果來說,這顯然太慢了。這個選項就可以用來設定每幀都更新
  • Color OpenGL Fast Path Blue 這個選項會對任何直接使用OpenGL繪制的圖層進行高亮
  • Flash Updated Region 這個選項會對重繪的内容高亮成黃色(也就是任何在軟體層面使用Core Graphics繪制的圖層)。這種繪圖的速度很慢。

界面頓卡的原因

界面頓卡主要從兩個角度考慮

CPU限制

  • 對象的建立,釋放,屬性調整。這裡尤其要提一下屬性調整,CALayer的屬性調整的時候是會建立隐式動畫的,是比較損耗性能的。
  • 視圖和文本的布局計算,AutoLayout的布局計算都是在主線程上的,是以占用CPU時間也很多 。U
  • 文本渲染,諸如UILabel和UITextview都是在主線程渲染的
  • 圖檔的解碼,這裡要提到的是,通常UIImage隻有在交給GPU之前的一瞬間,CPU才會對其解碼。

GPU限制

  • 視圖的混合。比如一個界面十幾層的視圖疊加到一起,GPU不得不計算每個像素點藥顯示的像素
  • 離屏渲染。視圖的Mask,圓角,陰影。
  • 半透明,GPU不得不進行數學計算,如果是不透明的,CPU隻需要取上層的就可以了
  • 浮點數像素

界面頓卡的優化

建議使用成熟的”輪子”,因為作為一個開發者,你的工作是寫出高品質的App,那麼為什麼不用那些已經驗證成功的架構呢?如果真的輪子不能實作,或者你有閑下來的時間,再造輪子未嘗不可。

使用AsyncDisplayKit

使用FaceBook出品的AsyncDisplayKit來寫複雜的界面。能夠獲得異步繪制,預先加載等諸多好處。不過,需要一定的學習成本,前段時間看了下網易新聞的安裝包,就使用了AsyncDisplayKit

圖文混排引擎

大多數性能要求較高的界面就是圖文混排,比如微網誌Feed,微信朋友圈等界面。建議使用成熟的圖文混排引擎,因為這些引擎一般支援異步繪制,并且做了大量優化。推薦兩個

  • YYKit
  • DTCoreText

異步繪制

把複雜的界面,放到背景線程裡繪制成一個bitmap,然後再顯示。雖然有些延遲,不過換來的卻是平滑的界面。

圖檔的解碼

建議使用成熟的庫,比如SDWebImage等,能夠在背景進行圖檔解碼,減少CPU的使用。

預加載與緩存

對于複雜的TableView,可以對Cell視圖的各個控件的大小,位置背景進行預計算,并且緩存起來。這樣保證在

heightForRow

cellForRow

中不進行大量的計算。

盡量使用CALayer

因為Layer是一個輕量級的視圖結構,它不接受通知,不接受觸摸,不在響應鍊。是以,相對于UIView來說,它的性能較好。并且CALayer及其子類是可以使用GPU渲染的,能夠硬體加速。

圖層預合成

将兩個CALayer的内容合成到一個Bitmap裡,然後顯示。能夠減輕GPU的壓力

資料

建議看看這幾篇文章

  • objc.io-繪制像素到螢幕上
  • YYKit的作者:iOS 保持界面流暢的技巧
  • iOS 核心動畫進階及技巧

轉載自:http://blog.csdn.net/shaobo8910/article/details/66975785

繼續閱讀