在Android Studio Logcat中過濾關鍵字「Displayed」,能夠看到對應的冷啓動耗時日誌。html
使用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能夠對業務邏輯的各個部分進行隔離,從而使得業務邏輯各部分之間的耦合性下降,提升程序的可重用性,同時大大提升了開發效率。
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通常定位在以下位置:
首先,咱們舉一個小栗子:
@Before("execution(* android.app.Activity.on**(..))")
public void onActivityCalled(JoinPoint joinPoint) throws Throwable {
...
}
複製代碼
在execution中的是一個匹配規則,第一個*表明匹配任意的方法返回值,後面的語法代碼匹配全部Activity中on開頭的方法。
處理Join Point的類型:
如何統計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'
檢測開始代碼處添加:
Debug.startMethodTracing();
檢測結束代碼處添加:
Debug.stopMethodTracing();
使用adb pull將生成的**.trace文件導出到電腦,而後使用Android Studio的Profiler加載
打開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小結
特色
做用 主要作熱點分析,獲得兩種數據:
使用方式:代碼插樁
定義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
複製代碼
具體參數含義以下:
如何查看數據?
在UIThread一欄能夠看到核心的系統方法時間區域和咱們本身使用代碼插樁捕獲的方法時間區域。
Systrace原理
在系統的一些關鍵鏈路(如SystemServcie、虛擬機、Binder驅動)插入一些信息(Label); 經過Label的開始和結束來肯定某個核心過程的執行時間; 把這些Label信息收集起來獲得系統關鍵路徑的運行時間信息,最後獲得整個系統的運行性能信息; Android Framework裏面一些重要的模塊都插入了label信息,用戶App中能夠添加自定義的Lable。
Systrace小結
特性
結合Android內核的數據,生成Html報告。 系統版本越高,Android Framework中添加的系統可用Label就越多,可以支持和分析的系統模塊也就越多。 必須手動縮小範圍,會幫助你加速收斂問題的分析過程,進而快速地定位和解決問題。
做用
主要用於分析繪製性能方面的問題。 分析系統關鍵方法和應用方法耗時。
結合AOP,能夠在方法的先後,很是方便地批量插入如下代碼。最後從運行生成Html報告後,能夠快速查找出耗時的方法。
Trace.begainSection();
Trace.endSection();
複製代碼