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

相关文章
相关标签/搜索