一、簡介
TraceView 是 Android SDK 中內(nèi)置的一個(gè)工具,它可以加載 trace 文件,用圖形的形式展示代碼的執(zhí)行時(shí)間、次數(shù)及調(diào)用棧,主要便于我們分析及優(yōu)化方法的執(zhí)行.
官方文檔對(duì)TraceView的說明講得非常簡單,僅供參考吧:https://developer.android.com/studio/profile/traceview
二、生成和分析traceView文件
方式1:使用代碼
在目標(biāo)代碼塊前后加 trace 針對(duì)具體代碼位置檢測(cè)
android.os.Debug.startMethodTracing()
// 目標(biāo)代碼塊
android.os.Debug.stopMethodTracing()
當(dāng)你調(diào)用開始代碼的時(shí)候,系統(tǒng)會(huì)生產(chǎn) trace 文件,并且產(chǎn)生追蹤數(shù)據(jù),當(dāng)你調(diào)用結(jié)束代碼時(shí),會(huì)將追蹤數(shù)據(jù)寫入到 trace 文件中: /sdcard/Android/data/包名/files/dmtrace.trace 文件
下一步使用 adb 命令將 trace 文件導(dǎo)出到電腦:
adb pull /sdcard/shixintrace.trace /tmp
使用代碼生成 trace 方式的好處是容易控制追蹤的開始和結(jié)束,缺點(diǎn)就是步驟稍微多了一點(diǎn)。
方式2: Android Studio 中 monitor 點(diǎn)擊鬧鐘按鈕

生成文件打開效果:

優(yōu)點(diǎn):矩形圖展示執(zhí)行時(shí)間和調(diào)用關(guān)系還是比較直觀的
缺點(diǎn):左上角可以切換線程,但是無法將多個(gè)線程在同一平面做直觀對(duì)比,稍微有點(diǎn)不方便。
方式3(推薦,本文主要使用的方式):DDMS
在 DDMS 中, 選中進(jìn)程, 點(diǎn)擊 Start Method Profiling,點(diǎn)擊后變灰色,叫Stop Method Profiling,再點(diǎn)擊結(jié)束獲取信息,生成trace文件。

生成文件效果:

上圖界面分兩部分, 上面是時(shí)間線面板, 下面是分析面板
<1>時(shí)間線面板 (Timeline Panel) 展示了不同線程的執(zhí)行時(shí)間
其中不同的顏色表示不同的方法
同一個(gè)顏色脈沖 bar越長,說明執(zhí)行時(shí)間越久,如圖中的主線程 main
顏色脈沖 bar 的高度表示 cpu 的利用率,高度越高表示 cpu 利用率越高
空白表示這個(gè)時(shí)間段內(nèi)沒有執(zhí)行內(nèi)容
黑塊表示系統(tǒng)空閑(system idle)
交互操作:
放大: 鼠標(biāo)選中線程的顏色部分, 水平拉動(dòng)可以放大圖
還原: 雙擊時(shí)間線面板右上角dual click位置
縮?。耗壳斑€不知道怎么縮小 - - |||
<2>分析面板 (Profile Panel) 展示了不同方法的執(zhí)行時(shí)間信息
函數(shù)調(diào)用關(guān)系
點(diǎn)一個(gè)方法后可以看到有兩部分,一個(gè)是 Parents,另一個(gè)是 Children。

關(guān)鍵指標(biāo)
| 列名 | 描述 |
|---|---|
| Name | 該線程運(yùn)行過程中所調(diào)用的函數(shù)名 |
| Incl Cpu Time % | 表示以時(shí)間百分比來統(tǒng)計(jì)的 Incl Cpu Time |
| Incl Cpu Time | 某函數(shù)占用的 CPU 時(shí)間,包含內(nèi)部調(diào)用其它函數(shù)的 CPU 時(shí)間 |
| Excl Cpu Time % | 表示以時(shí)間百分比來統(tǒng)計(jì)的 Excl Cpu Time |
| Excl Cpu Time | 某函數(shù)占用的 CPU 時(shí)間,但不含內(nèi)部調(diào)用其它函數(shù)所占用的 CPU 時(shí)間 |
| Incl Real Time % | 表示以時(shí)間百分比來統(tǒng)計(jì)的 Incl Real Time |
| Incl Real Time | 某函數(shù)運(yùn)行的真實(shí)時(shí)間 (以毫秒為單位),內(nèi)含調(diào)用其它函數(shù)所占用的真實(shí)時(shí)間 |
| Excl Real Time % | 表示以時(shí)間百分比來統(tǒng)計(jì)的 Excl Real Time |
| Excl Real Time | 某函數(shù)運(yùn)行的真實(shí)時(shí)間 (以毫秒為單位),不含調(diào)用其它函數(shù)所占用的真實(shí)時(shí)間 |
| Call + Recur Calls / Total | 某函數(shù)被調(diào)用次數(shù)以及遞歸調(diào)用占總調(diào)用次數(shù)的百分比 |
| Cpu Time / Call | 某函數(shù)調(diào)用 CPU 時(shí)間與調(diào)用次數(shù)的比。相當(dāng)于該函數(shù)平均執(zhí)行時(shí)間 |
| Real Time / Call | 同CPU Time/Call類似,只不過統(tǒng)計(jì)單位換成了真實(shí)時(shí)間 |
定位問題:
定位問題時(shí) TraceView 的使用方式:
1)從上半部分查看哪些線程執(zhí)行時(shí)間長?什么時(shí)候開始執(zhí)行?與主線程交錯(cuò)時(shí)間?
哪些方法的執(zhí)行需要花費(fèi)很長時(shí)間
2)點(diǎn)擊 TraceView 中的 Cpu Time/Call,按照占用 CPU 時(shí)間從高到低排序
哪些方法調(diào)用次數(shù)非常頻繁
3)點(diǎn)擊 TraceView 中的 Calls + Recur Calls/Total ,按照調(diào)用次數(shù)從高到底排序
排序后,然后逐個(gè)排查是否有項(xiàng)目代碼或者依賴庫代碼,有的話點(diǎn)擊查看詳情,查看是這個(gè)方法還是調(diào)用的子方法的問題,進(jìn)一步定位問題。
三、案例分析
案例:
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
findViewById(R.id.btn).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
computeFibonacci(50);
}
});
}
public int computeFibonacci(int positionInFibSequence) {
//0 1 1 2 3 5 8
if (positionInFibSequence <= 2) {
return 1;
} else {
return computeFibonacci(positionInFibSequence - 1)
+ computeFibonacci(positionInFibSequence - 2);
}
}
}
通過點(diǎn)擊Button調(diào)用computeFibonacci()函數(shù)在遞歸調(diào)用 將項(xiàng)目運(yùn)行起來
啟動(dòng)TraceView:

生成分析文件

看看函數(shù)執(zhí)行時(shí)間軸面板

滑動(dòng)鼠輪進(jìn)行放大

詳細(xì)信息面板:


從而找到問題:computeFibonacci遞歸調(diào)用導(dǎo)致占用CPU太多時(shí)間
優(yōu)化:
//代碼優(yōu)化前
public int computeFibonacci(int positionInFibSequence) {
//0 1 1 2 3 5 8
if (positionInFibSequence <= 2) {
return 1;
} else {
return computeFibonacci(positionInFibSequence - 1)
+ computeFibonacci(positionInFibSequence - 2);
}
}
//代碼優(yōu)化后
//將遞歸換為for循環(huán) 同時(shí)使用緩存 先將結(jié)果緩存起來
public int computeFibonacci(int positionInFibSequence) {
int prev=0;
int current=1;
int values;
for(int i=0;i<positionInFibSequence;i++){
values=prev+current;
prev=current;
current=values;
}
return current;
}
在運(yùn)行項(xiàng)目后使用TraceView工具進(jìn)行觀察 很明顯時(shí)間軸面板干凈多了:

總結(jié):traceView主要作用是針對(duì)項(xiàng)目中具體方法的耗時(shí)進(jìn)行優(yōu)化分析,一般是集合systrace一起使用。systrace懷疑到具體耗時(shí)方法,然后通過traceView來確認(rèn)。
參考:
https://blog.csdn.net/u011240877/article/details/54347396
http://www.itdecent.cn/p/d3c03c291093