效能優化工具知識梳理(1) TraceView

澤毛發表於2017-12-21

一、概述

使用Systrace需要開發者對於整個渲染的原理有較深的理解,而TraceView則更為直觀,你可以通過它來分析在一段時間應用內各個執行緒的執行情況,它會幫你計算出每個方法的具體耗時,這樣我們就可以瞭解到方法執行的效率,定位到當前效能的瓶頸在哪,從而考慮將一些耗時的操作放在子執行緒中進行,或者延後執行來優化應用的啟動速度和解決卡頓問題。 和之前一樣,我們分幾個部分介紹它:

  • 獲取TraceView的分析報表
  • 分析報表的格式
  • 具體案例

二、獲取*.trace報表

  • 第一步:點選Android Studio中的Tools/Android/Android Device Monitor,開啟除錯介面。
  • 第二步:如下面截圖所示,選中要分析的應用包名,點選Start Method Profiling按鈕,之後就會開始跟蹤:
    效能優化工具知識梳理(1)   TraceView
  • 第三步:進入應用內進行操作,操作完畢後,再次點選上面的按鈕Stop Method Profiling,等待一會,就會在右邊的視窗生成分析的報表,將滑鼠上移到紅框的檔名處,可以看到儲存的位置,我們可以把它儲存起來以便之後分析跟蹤問題:
    效能優化工具知識梳理(1)   TraceView

三、分析*.trace報表

獲取完報表之後,我們就可以通過它來分析,這個區域分為三個部分:

效能優化工具知識梳理(1)   TraceView

  • 紅色區域:列出了執行的各個執行緒。
  • 藍色區域:執行緒在一段時間內的執行情況,我們點選有顏色的地方,就可以定位到具體做了哪些操作。
  • 紫色區域:方法呼叫的具體情況。

前面兩個區域都比較好理解,我們主要看一下紫色區域的每一列具體的含義:

效能優化工具知識梳理(1)   TraceView

上面的表格中,一部分單位是百分比,另一部分是ms,要注意區別,除此之外,有兩點需要解釋一下:

  • InclExcl的概念 關於InclExcl的概念可以用下面這段程式碼來表示:
    public static void inclExcl(Context context) { //這個函式的執行時間為 Incl Real Time
        //假如這裡沒有呼叫任何函式,那麼這裡的執行時間就是:Excl Real Time
        writeSomething(context, 1000); //這裡的執行時間是:Incl Real Time - Excl Real Time
    }
複製程式碼
  • Cpu TimeReal Time的區別 Real Time表示的是一個函式從開始到執行時候所佔用的時間,而CPU Time則表示CPU執行這段函式所耗費的時間。 舉個例子,假如我們一個函式doSomething()CPU執行它首先花了time1的時間,之後CPU被分配用去執行別的函式花了time2,執行完之後繼續回來執行doSomething(),花了time3的時間把它執行完,那麼doSomething()Real Time就等於time1 + time2 + time3,而Cpu Time則等於time1 + time3

我們可以通過點選具體的列進行排序,在平時的分析中,我們主要關注一下:

  • CPU Time / Call較高 這一列表示函式的單個執行時間較長,這裡往往是可以優化的點:

  • 分析該函式的實現方式,能夠用其它的方法來實現,從而減少函式的執行時間

  • 分析該函式所執行的執行緒,如果可以那麼把它放到子執行緒中執行

  • 分析該函式所呼叫的時機,避免在應用啟動,或者做動畫的過程中執行它,否則會導致啟動速度變慢和介面卡頓。

  • CPU Time較高,但CPU Time / Call不高 這一列表示函式的單個執行時長不長,但呼叫的次數很多,這同樣是可以優化的點,需要看一下是否有必要在每個地方都呼叫它,能否進行延後操作,統計到一個地方執行。

  • Android相關的某些函式的Real Time: 由於我們的介面需要等到onCreateonResume等函式執行完之後,才會真正的顯示出來,因此,我們需要保證它們能夠儘快地執行完,也就是它的Incl Real Time儘可能地短: 例如下面兩點是最基本的:

  • onCreate

    效能優化工具知識梳理(1)   TraceView

  • onResume

    效能優化工具知識梳理(1)   TraceView

四、具體案例

我們分析一下在啟動過程中,由於佈局複雜或者耗時操作導致的問題: 首先我們看一下正常的情況:

  • callActivityOnCreate部分耗時為6.180ms
    效能優化工具知識梳理(1)   TraceView
  • callActivityOnResume耗時為1.219ms
    效能優化工具知識梳理(1)   TraceView

4.1 佈局層次過於複雜導致的問題

我們修改Activity的根佈局:

<FrameLayout
        android:background="@android:color/black"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
        <FrameLayout
            android:background="@android:drawable/screen_background_dark"
            android:layout_width="match_parent"
            android:layout_height="500dp">
            <FrameLayout
                android:background="@android:drawable/star_big_off"
                android:layout_width="match_parent"
                android:layout_height="400dp">
                <FrameLayout
                    android:background="@android:drawable/bottom_bar"
                    android:layout_width="match_parent"
                    android:layout_height="300dp">
                    <FrameLayout
                        android:background="@android:color/holo_blue_bright"
                        android:layout_width="match_parent"
                        android:layout_height="200dp">
                    </FrameLayout>
                </FrameLayout>
            </FrameLayout>
        </FrameLayout>
</FrameLayout>
複製程式碼

再次抓取之後,看一下onCreate的時間,發現耗時增加到17ms

效能優化工具知識梳理(1)   TraceView
之後再點選這個函式,分析裡面耗時最長的子方法,可以看到就是由於佈局引起的:
效能優化工具知識梳理(1)   TraceView

4.2 在啟動過程中進行耗時的操作

首先把佈局恢復成沒有問題的狀態,然後在onCreateonResume方法中增加不同的IO操作:

public class TraceViewActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_trace_view);
        TraceViewOperation.writeOnActivityOnCreate(this, 1000);
    }

    @Override
    protected void onResume() {
        super.onResume();
        TraceViewOperation.writeOnActivityOnResume(this, 1000);
    }

}
複製程式碼

其中onCreate在主執行緒中進行,而onResume裡面則另起了一個執行緒:

public class TraceViewOperation {

    public static void writeOnActivityOnCreate(Context context, int count) {
        writeSomething(context, count);
    }
    
    public static void writeOnActivityOnResume(final Context context, final int count) {
        new Thread() {
            @Override
            public void run() {
                super.run();
                writeSomething(context, count);
            }
        }.start();
    }

}
複製程式碼
  • onCreate耗時:
    效能優化工具知識梳理(1)   TraceView
    和上面類似,點進去看耗時的方法,正是由於我們在前面進行IO操作引起的:
    效能優化工具知識梳理(1)   TraceView
  • onResume耗時:
    效能優化工具知識梳理(1)   TraceView
    可以看到,由於我們是另起了一個執行緒進行操作,因此,並不會佔用它的執行時間。

五、小結

通過TraceView,我們可以瞭解到某些關鍵函式上的執行時間,正如前面第三點談到的,根據不同的情況進行分析和優化,將會有效地提高應用的啟動速度,避免出現卡頓現象。


更多文章,歡迎訪問我的 Android 知識梳理系列:

相關文章