調試工具Instruments----Core Animation

一、Core Animation 的作用

通過時間分析測量應用的圖形性能以及進程的CPU使用率。
用來監測Core Animation性能。它提供了周期性的FPS,并且考慮到了發生在程序之外的動畫。

  1. FPS是什么?
    任何屏幕總是有一個刷新率,比如iPhone推薦的刷新率是60Hz,也就是說GPU(圖形處理器)每秒鐘刷新屏幕60次,因此兩次刷新之間的間隔為16.67ms。這段時間內屏幕內容保持不變,稱為一幀(frame), fps表示frames per second,也就是每秒鐘顯示多少幀畫面。對于靜止不變的內容,我們不需要考慮它的刷新率,但在執行動畫或滑動時,fps的值直接反映出滑動的流程程度。

二、Core Animation 的調試選項

Core Animation的一系列復選框選項幫助調試渲染瓶頸。

  1. Color Blended Layers
    這個選項基于渲染程度對屏幕中混合區域進行綠到紅的高亮(也就是多個半透明圖層的疊加)。由于重繪的原因,混合對GPU性能會有影響,同時也是滑動或者動畫幀率下降的罪魁禍首之一。
    (1)圖層混合
    首先我們要明白像素的概念,屏幕上每一個點都是一個像素,像素有R、G、B三種顏色構成(有時候還帶有alpha值)。如果某一塊區域覆蓋了多個layer,最后的顯示效果受到了這些layer的共同影響。舉個例子,上層是藍色(RGB=0,0,1),透明度為50%,下層是紅色(RGB=1,0,0)。那么最終的顯示效果是紫色(RGB=0.5,0,0.5)。這種顏色的混合(blending)需要消耗一定的GPU資源,因為實際上可能不只有兩層。如果只想顯示最上面的藍色,可以把它的透明度設置為100%,這樣GPU會忽略下面所有的layer,從而節約了很多不必要的運算。

假如最上層的view是不透明的,那直接使用這個view的對應顏色之就可以,但如果view是透明的,在計算像素的顏色值時就需要計算它下面圖層,透明的視圖越多,計算量就越大,因此也會對圖形的性能產生一定的影響,所以可以的話也盡量減少透明圖層的數目。

(2)調試Color Blended Layers
Color Blended Layers 正是用于檢測哪里發生了圖層混合,并用紅色標記出來。因此,我們需要盡可能減少看到紅色區域。一旦發現應該想方設法消除它。開始調試后勾選這個選項,我們在真機上便可以看到效果。

  1. Color Hits Green and Misses Red
    (1)光柵化
    光柵化是將layer預先渲染成位圖(bitmap),然后加入緩存中。如果對于陰影效果這樣比較消耗資源的靜態庫內容進行緩存,可以得到一定幅度的性能提升。demo中的這一行代碼表示將label的layer光柵化:
    label.layer.shouldRasterize = YES;
    (2)調試Color Hits Green and Misses Red
    它表示如果命中緩存則表示為綠色,否則顯示為紅色,顯然綠色越多越好,紅色越少越好。
    注意:光柵化的核心在于緩存的思想。我們動手把玩一下,可以發現以下幾個有意思的現象:

上下微小幅度滑動時,一直是綠色上下大幅度滑動,新出現的label一開始是紅色,隨后變成綠色,如果靜止一秒鐘,剛開始滑動會變紅。

這是因為layer進行光柵化后渲染成位圖放在緩存中。當屏幕出現滑動時,我們之間從緩存中讀取而不必渲染,所以會看到綠色。當新的label出現時,緩存中沒有這label的位圖,所以會變成紅色。第三點比較關鍵,緩存中的對象有效期只有100ms,即使如果在 0.1s 內沒有被使用就會自動從緩存中清理出去。這就是為什么停一會再滑動就會看到紅色的原因。
光柵化的緩存機制是一把雙刃劍,先寫入緩存再讀取有可能銷毀較多的時間。因此光柵化僅適用于較復雜的、靜態的效果。通過Instrument的調試發現,這里使用光柵化經常出現未命中緩存的情況,如果沒有特殊需要則可以關閉光柵化,所以我們做的第二個優化是注釋掉下面這行代碼:
//label.layer.shouldRasterize = YES;

  1. Color Copied Images
    (1)顏色格式
    像素在內存中的布局和它在磁盤中的存儲方式并不相同。考慮一種簡單的情況:每個像素有R、G、B和alpha四個值,每個值占有1個字節,因此每個像素占有4字節的內存空間。一張1920*1080的照片(iPhone6Plus的分辨率)一共有2,073,600個像素,因此占用了超過8Mb的內存。但是一張同樣分辨率的PNG格式或JPEG格式的圖片一般情況下不會有這么大。這是因為JPEG將像素數據進行了非常復雜且可逆的轉化。
    CPU主要處理兩件事:
  • 把圖片從PNG或JPEG等格式中解壓處理,得到像素數據。
  • 如果GPU不支持這種顏色格式,CPU需要進行格式轉換。

比如應用中有一些從網絡下載的圖片,而GPU恰好不支持這個格式,這就需要CPU預先進行格式轉化。** 如果在主線程做這個操作對性能會有一定的影響。**
(2)調試Color Copied Images
Color Copied Images 就用來監測這種實時的格式轉化,如果有則會將圖片標記會藍色。
有時候寄宿圖片的生成意味著Core Animation被強制生成一些圖片,然后發送到渲染服務器,而不是簡單指向原始指針。復制圖片對內存和CPU使用來說都是一項非常昂貴的操作,所以應該盡可能的避免。

  1. Color Misaligned Images
    (1)圖片大小
    (2)調試Color Misaligned Images
    這里會高亮那些被縮放或者拉伸以及沒有正確對齊到像素邊界的圖片(也就是非整型坐標)。這些中的大多數通常會導致圖片的不正??s放,如果把一張大圖當縮略圖顯示,或者不正確的模糊圖像,那么這個選擇將會幫你識別出問題的所在。
    被縮放的圖片會被標記為黃色,像素不齊則會標記為紫色

  2. Color Offscreen-Rendered Yellow
    (1)offscreen-render
    什么是offscreen-render?
    offscreen-render涉及的內容比較多,有offscreen-render那就有onscreen render,onscreen render指的是GPU在當前用于顯示的屏幕緩沖區進行渲染,相反offscreen-render就是不在當前的屏幕緩存區,而在另外的緩沖區進行渲染,offscreen-render有兩種形式:

  • CPU的offscreen-render
    使用CPU來完成渲染操縱,通常在你使用:
    • drawRect (如果沒有自定義繪制的任務就不要在子類中寫一個空的drawRect方法,因為只要實現了該方法,就會為視圖分配一個寄宿圖,這個寄宿圖的像素尺寸等于視圖大小乘以 contentsScale的值,造成資源浪費)
    • 使用Core Graphics
      首先分配一塊內存,然后進行渲染操作生成一份bitmap位圖,整個渲染過程會在你的應用中同步的進行,接著再將位圖打包發送到iOS里一個單獨的進程--render server,理想情況下,render server將內容交給GPU直接顯示到屏幕上。
  • GPU的offscreen-render
    使用GPU在當前屏幕緩沖區以外開辟一個新的緩沖區進行繪制,通常發生的情況有:
    設置cornerRadius, masks, shadows,edge antialiasing等
    設置layer.shouldRasterize = YES

offscreen-render對性能到底有什么影響?
通常大家說的離屏渲染指的是GPU這塊(當然CPU這塊也會有影響,也需要消耗一定的資源),比如修改了layer的陰影或者圓角,GPU需要做額外的渲染操作。通常GPU在做渲染的時候是很快的,但是涉及到offscreen-render的時候情況就可能有些不同,因為需要額外開辟一個新的緩沖區進行渲染,然后繪制到當前屏幕的過程需要做onscreen跟offscreen上下文之間的切換,這個過程的消耗會比較昂貴,涉及到OpenGL的pipeline跟barrier,而且offscreen-render在每一幀都會涉及到,因此處理不當肯定會對性能產生一定的影響,所以可以的話盡量減少offscreen-render的圖層。
(2)調試Color Offscreen-Rendered Yellow
標示哪些layer需要做離屏渲染(offscreen-render)。這里會把哪些需要離屏渲染的圖層高亮成黃色。這些圖層很有可能需要用 'shadowPath' 或者 'shouldRasterize'來優化。

  1. Color OpenGL Fast Path Blue
    這個選項會對任何直接使用OpenGL繪制的圖層進行高亮。如果僅僅使用UIKit或者Core Animation的API,那么不會有任何效果。如果使用GLKView或者CAEAGLLayer,那如果不顯示藍色塊的話就意味著你正在強制CPU渲染額外的紋理,而不是繪制到屏幕。

  2. Flash Updated Regions
    這個選項會對重繪的內容高亮成黃色(也就是任何在軟件層面使用Core Graphics繪制的圖層)。這種繪圖的速度很慢。如果頻繁發生這種情況的話,這意味著有一個隱藏的bug或者說通過增加緩存或者使用替代方案會有提升性能的空間。

當碰到性能問題時,可以思考以下方面:

  • 是否受到CPU或者GPU的限制?
  • 是否有不必要的CPU渲染?
  • 是否有太多的離屏渲染操作?
  • 是否有太多的圖層混合操作?
  • 是否有奇怪的圖片格式或者尺寸?
  • 是否涉及到昂貴的view或者效果?
  • view的層次結構是否合理?

那么哪些是你最該開始考慮的方向呢?通常發生圖形性能問題的時候,比如列表滑動不順暢、動畫卡頓等,大部分都是由于Offscreen Rendering(離屏渲染)或者blending導致的,因為這在動畫的每一幀都會涉及到。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容