Android 性能優化 - 完全解決內存抖動

起源

內存抖動是因爲短期內有大量對象進出新生區致使的,它伴隨着頻繁的GC。 gc會大量佔用ui線程和cpu資源,會致使app總體卡頓android

android profile 效果圖以下圖數組

Memory 中緩存

這裏寫圖片描述

咱們能夠看到 上面的一溜白色垃圾桶。說明在大量的執行gc操做。用了一下子 手機就開始卡了bash

學習內容

  • android studio 3.0 編譯器 查看內存抖動
  • 使用工具來快速定位 引發內存抖動的代碼。
  • 學習 到什麼樣的 錯誤操做會致使內存都懂,如何避免。

快速定位內存抖動

快速定位 還得使用ddms。莫慌 as裏面自帶了 Tools->Android->Android Device Monitor 而後進行以下操做app

這裏寫圖片描述

而後咱們看以下圖片。 dom

這裏寫圖片描述

不要慌。ide

中間紅框的就是咱們要分析的內容,看他良莠不齊的就是 內存抖動形成的。函數

而後咱們把紅框 內容放大。鼠標點住 而後往右拖動,就會變大,點擊 紅框上面的數字就會變小。工具

這裏寫圖片描述

咱們將 抖動的地方 放大後。隨便點擊會出現下圖樣式學習

這裏寫圖片描述

能夠看到這個粉色的拱門的 圖案。從它的左邊到右邊 表明 一個函數 消耗的時間。

咱們接下來 就快速定位有問題的代碼在哪裏

這裏寫圖片描述

我就隨便的滑動了一下,而後 隨便的選中了一個, 而後下邊就展現了 我所選中的 函數方法。

這裏有一個細節

這裏寫圖片描述

  • onClick 最前面 的序號是 9
  • Parent 下的方法 序號爲8
  • children 下的方法序號爲10

說明 onClick 的序號 大於onClick 調用的方法 的序號。小於 onClick 被調用的方法的序號。

若是咱們一直點擊Parent 下的方法就會找到 序號爲1 的方法

以下圖所示。

這裏寫圖片描述

咱們找到了錯誤代碼在哪。那麼咱們就看一下 源代碼的樣子

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        findViewById(R.id.button1).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                imPrettySureSortingIsFree();

            }
        });
    }

    /**
     *  排序後打印二維數組,一行行打印
     */
    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 += ", ";
                }
            }
        }


    }

    public int[] getSorted(int[] input) {
        int[] clone = input.clone();
        Arrays.sort(clone);
        return clone;
    }

}

複製代碼

發現 rowAsStr 對象在被不斷地建立。 咱們能夠把它優化一下

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        findViewById(R.id.button1).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                imPrettySureSortingIsFree();

            }
        });
    }

    /**
     * &emsp;排序後打印二維數組,一行行打印
     */
    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();
            }
        }

        //優化之後
        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);
        }

    }

    public int[] getSorted(int[] input) {
        int[] clone = input.clone();
        Arrays.sort(clone);
        return clone;
    }

}

複製代碼

這樣就不會內存抖動了

能找到問題,這個問題就基本解決了。

下面是避免發生內存抖動的幾點建議:

  • 儘可能避免在循環體內建立對象,應該把對象建立移到循環體外。
  • 注意自定義View的onDraw()方法會被頻繁調用,因此在這裏面不該該頻繁的建立對象。
  • 當須要大量使用Bitmap的時候,試着把它們緩存在數組中實現複用。
  • 對於可以複用的對象,同理可使用對象池將它們緩存起來。

其餘

分析面板 面板列名含義以下:

Name 方法的詳細信息,包括包名和參數信息
col 3 is right-aligned
col 2 is centered
zebra stripes are neat
Incl Cpu Time Cpu執行該方法該方法及其子方法所花費的時間
Incl Cpu Time % Cpu執行該方法該方法及其子方法所花費佔Cpu總執行時間的百分比
Excl Cpu Time Cpu執行該方法所話費的時間
Excl Cpu Time % Cpu執行該方法所話費的時間佔Cpu總時間的百分比
Incl Real Time 該方法及其子方法執行所話費的實際時間,從執行該方法到結束一共花了多少時間
Incl Real Time % 上述時間佔總的運行時間的百分比
Excl Real Time % 該方法自身的實際容許時間
Excl Real Time 上述時間佔總的容許時間的百分比
Calls+Recur 調用次數+遞歸次數,只在方法中顯示,在子展開後的父類和子類方法這一欄被下面的數據代替
Calls/Total 調用次數和總次數的佔比
Cpu Time/Call Cpu執行時間和調用次數的百分比,表明該函數消耗cpu的平均時間
Real Time/Call 實際時間於調用次數的百分比,該表該函數平均執行時間

參考

https://www.youtube.com/watch?v=McAvq5SkeTk

相關文章
相關標籤/搜索