1. 程式人生 > >效能優化之卡頓分析-計算並優化記憶體抖動和耗時操作

效能優化之卡頓分析-計算並優化記憶體抖動和耗時操作

1 卡頓(卡UI執行緒)

(1)外部引起的:Activity裡面直接進行網路訪問/大檔案的IO操作。
(2)記憶體引起的:記憶體抖動的問題,new Object obj = null;執行耗時方法。
(3)View本身的卡頓:自定義View要注意的,能否優化:

2 優化主方向

(1)避免讓主執行緒執行耗時的操作
(2)優化自定義View卡頓問題

3 解決方法(有問題???)

3.1 步驟一:使用Allocation Tracing來定位大致的情況

3.2 步驟二:使用TraceView來確定詳細的問題所在

3.2.1 TraceView工具能做什麼?

  從程式碼層面分析效能問題,針對每個方法來分析,比如當我們發現我們的應用出現卡頓的時候,我們可以來分析出現卡頓時在方法的呼叫上有沒有很耗時的操作,關注以下兩個問題:
  (1)呼叫次數不多,但是每一次執行都很耗時
  (2)方法耗時不大,但是呼叫次數太多
  簡單一點來說就是:我們能找到頻繁被呼叫的方法,也能找到執行非常耗時的方法,前者可能會造成Cpu頻繁呼叫,手機發燙的問題,後者就是卡頓的問題

3.2.2 參考連結

3.2.3 TraceView工具啟動

(1)開啟App操作應用後,start開始追蹤,點選stop後停止追蹤並且自動開啟traceview分析面板:
這裡寫圖片描述
這裡寫圖片描述
(2)開啟traceview分析面板:
這裡寫圖片描述
  展開一個方法後可以看到有兩部分:Parent表示呼叫這個方法的方法,可以叫做父方法;Children表示這個方法中呼叫的其他方法,可以叫做子方法。
Profile面板中各列作用說明:
這裡寫圖片描述

3.2.4 記憶體抖動分析

(1)圖例演示
這裡寫圖片描述
這裡寫圖片描述
(2)找到問題所在:rowAsStr += “, “;

/**
 * com.example.android.mobileperf.compute.MemoryChurnActivity的以下方法:
 *  排序後列印二維陣列,一行行列印
 */
public void imPrettySureSortingIsFree() { // 優化以前 int dimension = 300; int[][] lotsOfInts = new int[dimension][dimension]; Random randomGenerator = new Random(); for(int i = 0; i < lotsOfInts.length; i++) { for (int j = 0; j < lotsOfInts[i].length; j++) { lotsOfInts[i][j] = randomGenerator.nextInt(); } } for
(int i = 0; i < lotsOfInts.length; i++) { String rowAsStr = ""; //排序 int[] sorted = getSorted(lotsOfInts[i]); //拼接列印 for (int j = 0; j < lotsOfInts[i].length; j++) { rowAsStr += sorted[j]; if(j < (lotsOfInts[i].length - 1)){ rowAsStr += ", "; } } } //優化以後 // StringBuilder sb = new StringBuilder(); // String rowAsStr = ""; // for(int i = 0; i < lotsOfInts.length; i++) { // //清除上一行 // sb.delete(0,rowAsStr.length()); // //排序 // int[] sorted = getSorted(lotsOfInts[i]); // //拼接列印 // for (int j = 0; j < lotsOfInts[i].length; j++) { //// rowAsStr += sorted[j]; // sb.append(sorted[j]); // if(j < (lotsOfInts[i].length - 1)){ //// rowAsStr += ", "; // sb.append(", "); // } // } // rowAsStr = sb.toString(); // Log.i("ricky", "Row " + i + ": " + rowAsStr); // } }

3.2.5 執行耗時方法

(1)圖例演示
這裡寫圖片描述
這裡寫圖片描述
(2)找到問題所在:遞迴問題導致

// com.example.android.mobileperf.compute.CachingActivity
//優化前
public int computeFibonacci(int pInFibSequence) {
   //0 1 1 2 3 5 8
   if (pInFibSequence <= 2) {
       return 1;
   } else {
       return computeFibonacci(pInFibSequence - 1)+ computeFibonacci(pInFibSequence - 2);
   }
}

//優化後的斐波那契數列的非遞迴演算法 caching快取+批處理思想
public int computeFibonacci(int pInFibSequence) {
    int prev = 0;
    int current = 1;
    int newValue;
    for (int i=1; i<pInFibSequence; i++) {
        newValue = current + prev;
        prev = current;
        current = newValue;
    }
    return current;
}

(3)解決問題思路
  儘量避免讓【主執行緒】執行耗時的操作,讓它能快速處理UI事件和Broadcast訊息。

4 如何使用Traceview計算某個類的耗時

(1)在onCreate開始和結尾打上trace.

 @Override
 protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    Debug.startMethodTracing("textracing");//開始

    sleep();
    login();

     Debug.stopMethodTracing();//結束
}

private void sleep() {
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

(2)執行程式, 會在手機sdcard或者本地儲存上生成一個”textracing.trace”的檔案。注意: 需要給程式加上寫儲存的許可權:

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

(3)MAC:通過adb pull將其匯出到本地,然後將textracing.trace從手機傳到電腦上

adb pull /sdcard/Traceview.trace ~/temp

(4)Windows:直接將textracing.trace從手機傳到電腦上(textracing.trace存放在根目錄)

(5)Android Studio直接開啟
這裡寫圖片描述

5 利用loop()中列印的日誌檢測應用中的UI卡頓