Android 快速定位耗時方法

1、啓動耗時檢測

一、查看Logcat

在Android Studio Logcat中過濾關鍵字「Displayed」,能夠看到對應的冷啓動耗時日誌。html

二、adb shell

使用adb shell獲取應用的啓動時間python

adb shell am start -W [packageName]/[AppstartActivity全路徑]android

執行後會獲得三個時間:ThisTime、TotalTime和WaitTime,詳情以下:web

ThisTime 最後一個Activity啓動耗時。shell

TotalTime 全部Activity啓動耗時。編程

WaitTime AMS啓動Activity的總耗時。json

通常查看獲得的TotalTime,即應用的啓動時間,包括建立進程 + Application初始化 + Activity初始化到界面顯示的過程。bash

特色:app

  • 線下使用方便,不能帶到線上。
  • 非嚴謹、精確時間。

三、AOP(Aspect Oriented Programming)打點

面向切面編程,經過預編譯和運行期動態代理實現程序功能統一維護的一種技術。函數

做用

利用AOP能夠對業務邏輯的各個部分進行隔離,從而使得業務邏輯各部分之間的耦合性下降,提升程序的可重用性,同時大大提升了開發效率。

AOP核心概念

1)、橫切關注點

對哪些方法進行攔截,攔截後怎麼處理。

2)、切面(Aspect

類是對物體特徵的抽象,切面就是對橫切關注點的抽象。

3)、鏈接點(JoinPoint)

被攔截到的點(方法、字段、構造器)。

4)、切入點(PointCut)

對JoinPoint進行攔截的定義。

5)、通知(Advice)

攔截到JoinPoint後要執行的代碼,分爲前置、後置、環繞三種類型。

準備 首先,爲了在Android使用AOP埋點須要引入AspectJ,在項目根目錄的build.gradle下加入:

classpath 'com.hujiang.aspectjx:gradle-android-plugin- aspectjx:2.0.0'

而後,在app目錄下的build.gradle下加入:

apply plugin: 'android-aspectjx'
implement 'org.aspectj:aspectjrt:1.8.+'
複製代碼

AOP埋點實戰 JoinPoint通常定位在以下位置:

  • 函數調用
  • 獲取、設置變量
  • 類初始化 使用PointCut對咱們指定的鏈接點進行攔截,經過Advice,就能夠攔截到JoinPoint後要執行的代碼。 Advice一般有如下幾種類型:
  • Before:PointCut以前執行
  • After:PointCut以後執行
  • Around:PointCut以前、以後分別執行

首先,咱們舉一個小栗子:

@Before("execution(* android.app.Activity.on**(..))")
public void onActivityCalled(JoinPoint joinPoint) throws Throwable {
...
}
複製代碼

在execution中的是一個匹配規則,第一個*表明匹配任意的方法返回值,後面的語法代碼匹配全部Activity中on開頭的方法。

處理Join Point的類型:

  • call:插入在函數體裏面
  • execution:插入在函數體外面

如何統計Application中的全部方法耗時?

@Aspect
public class ApplicationAop {
    @Around("call (* com.json.chao.application.BaseApplication.**(..))")
    public void getTime(ProceedingJoinPoint joinPoint) {
    Signature signature = joinPoint.getSignature();
    String name = signature.toShortString();
    long time = System.currentTimeMillis();
    try {
        joinPoint.proceed();
    } catch (Throwable throwable) {
        throwable.printStackTrace();
    }
    Log.i(TAG, name + " cost" +     (System.currentTimeMillis() - time));
    }
}
複製代碼

注意

當Action爲Before、After時,方法入參爲JoinPoint。 當Action爲Around時,方法入參爲ProceedingPoint。

Around和Before、After的最大區別:

ProceedingPoint不一樣於JoinPoint,其提供了proceed方法執行目標方法。

總結AOP特性:

  • 無侵入性
  • 修改方便

強烈推薦結合第三節講解的Systrace工具使用,能夠很是快速地定位到耗時方法,上線的時候,能夠考慮屏蔽掉AOP功能。

//apply plugin: 'android-aspectjx'

2、啓動速度分析工具 — TraceView

使用方式

方式1

檢測開始代碼處添加:

Debug.startMethodTracing();

檢測結束代碼處添加:

Debug.stopMethodTracing();

使用adb pull將生成的**.trace文件導出到電腦,而後使用Android Studio的Profiler加載

方式2

打開Profiler -> CPU -> 點擊 Record -> 點擊 Stop -> 查看Profiler下方Top Down/Bottom Up 區域找出耗時的熱點方法。

Profile CPU

一、Trace types

Trace Java Methods

會記錄每一個方法的時間、CPU信息。對運行時性能影響較大。

Sample Java Methods

相比於Trace Java Methods會記錄每一個方法的時間、CPU信息,它會在應用的Java代碼執行期間頻繁捕獲應用的調用堆棧,對運行時性能的影響比較小,可以記錄更大的數據區域。

Sample C/C++ Functions

需部署到Android 8.0及以上設備,內部使用simpleperf跟蹤應用的native代碼,也能夠命令行使用simpleperf。

Trace System Calls

檢查應用與系統資源的交互狀況。 查看全部核心的CPU瓶。 內部採用systrace,也可使用systrace命令。

二、Event timeline 顯示應用程序中在其生命週期中轉換不一樣狀態的活動,如用戶交互、屏幕旋轉事件等。

三、CPU timeline 顯示應用程序實時CPU使用率、其它進程實時CPU使用率、應用程序使用的線程總數。

四、Thread activity timeline 列出應用程序進程中的每一個線程,並使用了不一樣的顏色在其時間軸上指示其活動。

綠色:線程處於活動狀態或準備好使用CPU。 黃色:線程正等待IO操做。(重要) 灰色:線程正在睡眠,不消耗CPU時間。

Profile提供的檢查跟蹤數據窗口有四種

一、Call Chart

提供函數跟蹤數據的圖形表示形式。

水平軸:表示調用的時間段和時間。 垂直軸:顯示被調用方。 橙色:系統API。 綠色:應用自有方法 藍色:第三方API(包括Java API) 提示:右鍵點擊Jump to source跳轉至指定函數。

二、Flame Chart

將具備相同調用方順序的徹底相同的方法收集起來。

水平軸:執行每一個方法的相對時間量。 垂直軸:顯示被調用方。 注意:看頂層的哪一個函數佔據的寬度最大(平頂),可能存在性能問題。

三、Top Down

遞歸調用列表,提供self、children、total時間和比率來表示被調用的函數信息。 Flame Chart是Top Down列表數據的圖形化。

四、Bottom Up

展開函數會顯示其調用方。 按照消耗CPU時間由多到少的順序對函數排序。 注意點:

Wall Clock Time:程序執行時間。 Thread Time:CPU執行的時間。

TraceView小結

特色

  • 圖形的形式展現執行時間、調用棧等。
  • 信息全面,包含全部線程。
  • 運行時開銷嚴重,總體都會變慢,得出的結果並不真實。
  • 找到最耗費時間的路徑:Flame Chart、Top Down。
  • 找到最耗費時間的節點:Bottom Up。

做用 主要作熱點分析,獲得兩種數據:

  • 單次執行最耗時的方法。
  • 執行次數最多的方法。

3、啓動速度分析工具 — Systrace

使用方式:代碼插樁

定義Trace靜態工廠類,將Trace.begainSection(),Trace.endSection()封裝成i、o方法,而後再在想要分析的方法先後進行插樁便可。

在命令行下執行systrace.py腳本:

python /Users/quchao/Library/Android/sdk/platform-tools/systrace/systrace.py -t 20 sched gfx view wm am app webview -a "com.wanandroid.json.chao" -o ~/Documents/open-project/systrace_data/wanandroid_start_1.html
複製代碼

具體參數含義以下:

  • -t:指定統計時間爲20s。
  • shced:cpu調度信息。
  • gfx:圖形信息。
  • view:視圖。
  • wm:窗口管理。
  • am:活動管理。
  • app:應用信息。
  • webview:webview信息。
  • -a:指定目標應用程序的包名。
  • -o:生成的systrace.html文件。

如何查看數據?

在UIThread一欄能夠看到核心的系統方法時間區域和咱們本身使用代碼插樁捕獲的方法時間區域。

Systrace原理

在系統的一些關鍵鏈路(如SystemServcie、虛擬機、Binder驅動)插入一些信息(Label); 經過Label的開始和結束來肯定某個核心過程的執行時間; 把這些Label信息收集起來獲得系統關鍵路徑的運行時間信息,最後獲得整個系統的運行性能信息; Android Framework裏面一些重要的模塊都插入了label信息,用戶App中能夠添加自定義的Lable。

Systrace小結

特性

結合Android內核的數據,生成Html報告。 系統版本越高,Android Framework中添加的系統可用Label就越多,可以支持和分析的系統模塊也就越多。 必須手動縮小範圍,會幫助你加速收斂問題的分析過程,進而快速地定位和解決問題。

做用

主要用於分析繪製性能方面的問題。 分析系統關鍵方法和應用方法耗時。

結合AOP,能夠在方法的先後,很是方便地批量插入如下代碼。最後從運行生成Html報告後,能夠快速查找出耗時的方法。

Trace.begainSection();
Trace.endSection();
複製代碼
相關文章
相關標籤/搜索