介紹:
TraceView工具能做什么?
從代碼層面分析性能問題,針對每個方法來分析,比如當我們發現我們的應用出現卡頓的時候,我們可以來分析出現卡頓時在方法的調用上有沒有很耗時的操作,關注以下兩個問題:
- 調用次數不多,但是每一次執行都很耗時
- 方法耗時不大,但是調用次數太多
前言:
有時候,當你寫完代碼之后,你發現它的運行速度,比你預想的要慢,這種情況經常會無緣無故地出現,你專注于采用某種方法編寫代碼,來解決特定的問題,但是很快你發現代碼的運行時間過長,遠遠超過你的預期
緩慢的函數執行通常是由于兩方面的問題造成的:
- 是執行速度很慢的函數,這種函數很容易被發現。你的某些函數所花費的時間,超過你的預期2倍、10倍,甚至50倍,這種問題容易解決。只要找到那些運行很慢的函數,查看代碼找到問題所在,然后想辦法解決就可以了。
- 是當你有數以千計的函數時,每個函數所用的時間都額外增加一毫秒,從而導致整個程序執行速度變慢數百毫秒,這種類型的問題很難跟蹤,而且更難以解決,因為通常你需要分析,每段執行代碼才能發現這些小問題,這最終會影響你的產品發布,進而影響公司業績
- 總之就是在執行某些函數時大量的占用CPU時間片 導致頁面卡頓 如果硬件設備性能不好的話 應用就直接掛掉
Android SDK有一些很不錯的工具,幫助你找到這些有問題的代碼部分,讓你能夠立即解決它們,讓我們來了解它們
案例:
public class MainActivity extends AppCompatActivity {
Button btn_batching;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btn_batching = (Button) findViewById(R.id.btn_batching);
//計算斐波拉契列數
btn_batching.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
computeFibonacci(40);
}
});
}
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);
}
}
}
上面是一個非常簡單的例子 通過點擊Button調用computeFibonacci()函數在遞歸調用 將項目運行起來 再打開Android Monitor 進行分析:
點擊Button后CPU使用頻率明顯上升 如果是一個死循環 那么應用很將快就掛掉 現在我們使用TraceView工具(Device Monitor)來分析下到底是什么情況
**打開Android Device Monitor **
啟動TraceView
點擊 start Method Profiling后就開始執行我們的APP操作 我這里只有一個Button 點擊后就執行computeFibonacci(40)
等待大概5秒就stop Method Profiling 就會生成一份分析文件
由上圖看到的有三個面板 且也很直觀的看到了方法執行過程的樹狀圖黑壓壓的一片 想都不用想肯定出問題了 先看看函數執行時間軸面板
滑動鼠輪進行放大
詳細信息面板:
- Parents: 表示調用這個方法的方法 (MainActivtiy$.onClick 調用的)
- Children:表示這個方法中調用的其他方法(調用了computeFibonacci(1))
- Parents while recursive: 只有出現遞歸調用才會出現 表示遞歸調用時涉及的父函數
- Children while recursive: 只有出現遞歸調用才會出現 表示遞歸調用時涉及的子函數
列名 | 作用 |
---|---|
Name | 該進程中所調用的函數名稱 |
Incl Cpu Time | 函數占用的CPU時間,包含內部調用其它函數的CPU時間 |
Excl Cpu Time | 函數占用的CPU時間,但不包含內部調用其它函數所占用的CPU時間 |
Incl Real Time | 函數運行的真實時間(以毫秒為單位),內含調用其它函數所占用的真實時間 |
Excl Real Time | 函數運行的真實時間(以毫秒為單位),不包含調用其它函數所占用的真實時間 |
Calls+Recur Calls/Total | 函數被調用次數以及遞歸調用占總調用次數的百分比 |
Cpu Time/Call | 函數調用CPU時間與調用次數的比(該函數平均執行時間) |
Real Time/Call | 同CPU Time/Call類似,只不過統計單位換成了真實時間 |
通過上圖就可以看出是MainActivtiy.computeFibonacci(1)這個函數執行的時候發生了遞歸調用導致占用CPU太多時間 找到該函數進行代碼優化:
//代碼優化前
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);
}
}
//代碼優化后
//將遞歸換為for循環 同時使用緩存 先將結果緩存起來
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;
}
以上是針對算法的優化 如果項目代碼確實必須那樣寫的話 可以考慮使用分線程去執行 在運行項目后使用TraceView工具進行觀察 很明顯時間軸面板干凈多了:
最后:
在開發過程中,為了使項目跑的很順暢,所以我們要使用好各種工具 給大家推薦幾篇關于項目優化的文章:
使用Android Monitor分析項目查找內存泄漏
使用MAT (Memory Analyzer Tool)分析Andriod項目內存泄漏
Android 性能優化:使用 Lint 優化代碼、去除多余資源
leakcanary