借助profiler工具进行内存分析

作者: 卖炭少年炭治郎 | 来源:发表于2020-04-11 11:32 被阅读0次

官方链接

使用 Memory Profiler 查看 Java 堆和内存分配

工具说明

  • android studio 版本3.6.1

模拟内存问题场景

  1. 建立一个新的工程,把下面有问题的自定义VIew,引入到工程里面,最好是写两个activity,把下面自定义view引入到第二个SecondActivity里面,方便测试。
  <com.enjoy.memory.widget.IOSStyleLoadingView3
       android:layout_width="50dp"
       android:layout_height="50dp"
       android:layout_gravity="center" />
public class IOSStyleLoadingView3 extends View {

    private final Context context;
    private double radius;
    private double insideRadius;
    private float northwestXStart;
    private float northwestYStart;
    private float northXStart;
    private float northYStart;
    private float notheastXStart;
    private float notheastYStart;
    private float eastXStart;
    private float eastYStart;
    private float southeastXStart;
    private float southeastYStart;
    private float southXStart;
    private float southYStart;
    private float southwestXStart;
    private float southwestYStart;
    private float westXStart;
    private float westYStart;

    private float northwestXEnd;
    private float northwestYEnd;
    private float northXEnd;
    private float northYEnd;
    private float notheastXEnd;
    private float notheastYEnd;
    private float eastXEnd;
    private float eastYEnd;
    private float southeastXEnd;
    private float southeastYEnd;
    private float southXEnd;
    private float southYEnd;
    private float southwestXEnd;
    private float southwestYEnd;
    private float westXEnd;
    private float westYEnd;

    private int currentColor = 7;

    String color[] = new String[]{
            "#a5a5a5",
            "#b7b7b7",
            "#c0c0c0",
            "#c9c9c9",
            "#d2d2d2",
            "#dbdbdb",
            "#e4e4e4",
            "#e4e4e4"
    };

//    int[] colors = new int[8];

    public IOSStyleLoadingView3(Context context) {
        this(context, null, 0);
    }

    public IOSStyleLoadingView3(Context context, AttributeSet attrs) {
        this(context, null, 0);
    }

    public IOSStyleLoadingView3(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        this.context = context;
        radius = UIKits.dip2Px(context, 9);
        insideRadius = UIKits.dip2Px(context, 5);

//        for (int i = 0; i < color.length; i++) {
//            colors[i] = Color.parseColor(color[i]);
//        }
//        paint.setAntiAlias(true);
//        paint.setStrokeWidth(UIKits.dip2Px(context, 2));
//        paint.setStyle(Paint.Style.STROKE);
//        paint.setStrokeCap(Paint.Cap.ROUND);

    }

//    Path path = new Path();
//    Paint paint = new Paint();


    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        Paint paint = new Paint();

        paint.setAntiAlias(true);
        paint.setStrokeWidth(UIKits.dip2Px(context, 2));
        paint.setStyle(Paint.Style.STROKE);
        paint.setStrokeCap(Paint.Cap.ROUND);

        Path p1=new Path();
        paint.setColor(Color.parseColor(color[0]));
        p1.moveTo(northwestXStart, northwestYStart);
        p1.lineTo(northwestXEnd, northwestYEnd);
        canvas.drawPath(p1, paint);

        Path p2=new Path();
        paint.setColor(Color.parseColor(color[1]));
        p2.moveTo(northXStart, northYStart);
        p2.lineTo(northXEnd, northYEnd);
        canvas.drawPath(p2, paint);

        Path p3=new Path();
        paint.setColor(Color.parseColor(color[2]));
        p3.moveTo(notheastXStart, notheastYStart);
        p3.lineTo(notheastXEnd, notheastYEnd);
        canvas.drawPath(p3, paint);

        Path p4=new Path();
        paint.setColor(Color.parseColor(color[3]));
        p4.moveTo(eastXStart, eastYStart);
        p4.lineTo(eastXEnd, eastYEnd);
        canvas.drawPath(p4, paint);

        Path p5=new Path();
        paint.setColor(Color.parseColor(color[4]));
        p5.moveTo(southeastXStart, southeastYStart);
        p5.lineTo(southeastXEnd, southeastYEnd);
        canvas.drawPath(p5, paint);

        Path p6=new Path();
        paint.setColor(Color.parseColor(color[5]));
        p6.moveTo(southXStart, southYStart);
        p6.lineTo(southXEnd, southYEnd);
        canvas.drawPath(p6, paint);

        Path p7=new Path();
        paint.setColor(Color.parseColor(color[6]));
        p7.moveTo(southwestXStart, southwestYStart);
        p7.lineTo(southwestXEnd, southwestYEnd);
        canvas.drawPath(p7, paint);

        Path p8=new Path();
        paint.setColor(Color.parseColor(color[7]));
        p8.moveTo(westXStart, westYStart);
        p8.lineTo(westXEnd, westYEnd);
        canvas.drawPath(p8, paint);

    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        double centerX = getMeasuredWidth() / 2;
        double centerY = getMeasuredHeight() / 2;
        double leg = radius * Math.cos(Math.PI / 4);
        double insideLeg = insideRadius * Math.cos(Math.PI / 4);


        northwestXStart = (float) (centerX - leg);
        northwestYStart = (float) (centerY - leg);
        northXStart = (float) centerX;
        northYStart = (float) (centerY - radius);
        notheastXStart = (float) (centerX + leg);
        notheastYStart = (float) (centerY - leg);
        eastXStart = (float) (centerX + radius);
        eastYStart = (float) centerY;
        southeastXStart = (float) (centerX + leg);
        southeastYStart = (float) (centerY + leg);
        southXStart = (float) centerX;
        southYStart = (float) (centerY + radius);
        southwestXStart = (float) (centerX - leg);
        southwestYStart = (float) (centerY + leg);
        westXStart = (float) (centerX - radius);
        westYStart = (float) centerY;

        northwestXEnd = (float) (centerX - insideLeg);
        northwestYEnd = (float) (centerY - insideLeg);
        northXEnd = (float) centerX;
        northYEnd = (float) (centerY - insideRadius);
        notheastXEnd = (float) (centerX + insideLeg);
        notheastYEnd = (float) (centerY - insideLeg);
        eastXEnd = (float) (centerX + insideRadius);
        eastYEnd = (float) centerY;
        southeastXEnd = (float) (centerX + insideLeg);
        southeastYEnd = (float) (centerY + insideLeg);
        southXEnd = (float) centerX;
        southYEnd = (float) (centerY + insideRadius);
        southwestXEnd = (float) (centerX - insideLeg);
        southwestYEnd = (float) (centerY + insideLeg);
        westXEnd = (float) (centerX - insideRadius);
        westYEnd = (float) centerY;
    }

    @Override
    protected void onAttachedToWindow() {
        super.onAttachedToWindow();
        startAnimation();
    }



    private ValueAnimator valueAnimator;

    public void startAnimation() {
        valueAnimator = ValueAnimator.ofInt(7, 0);
        valueAnimator.setDuration(400);
        valueAnimator.setRepeatCount(ValueAnimator.INFINITE);
        valueAnimator.setInterpolator(new LinearInterpolator());
        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                if ((int) animation.getAnimatedValue() != currentColor) {
                    String b[] = new String[color.length];//移动后的数组
                    for (int c = 0, size = color.length - 1; c < size; c++) {
                        b[c + 1] = color[c];
                    }
                    b[0] = color[color.length - 1];
                    color = b;
                    invalidate();
                    currentColor = (int) animation.getAnimatedValue();
                }
            }
        });
        valueAnimator.start();
    }

}

  1. 启动工程,打开有自定义view的页面

利用Profiler工具进行内存分析

  1. 找到profiler按钮的位置,打开


    在这里插入图片描述
  2. 点击➕号,选择你的进程


    在这里插入图片描述
  3. 选择MEMORY,因为我们分析的是内存问题,我们会看到Total的总数是一直在增加的,也就是说不断有新对象产生。

  4. 点击Record按钮,记录一段时间内程序产生的新对象


    image.png

通过分析上图,得知一段时间内增加的对象有Paint,Path,String,进一步点击追查发现,是在自定义view的onDraw方法中频繁的创造了这些对象

问题解决与总结

1.在ondraw方法中不要频繁的new对象,因为动画导致ondraw方法频繁调用,就导致了之前的代码频繁的创建一些对象。

   Path path = new Path();
   Paint paint = new Paint();


   @Override
   protected void onDraw(Canvas canvas) {
       super.onDraw(canvas);

       path.reset();
       paint.setColor(colors[currentColor++%8]);
       path.moveTo(northwestXStart, northwestYStart);
       path.lineTo(northwestXEnd, northwestYEnd);
       canvas.drawPath(path, paint);

       path.reset();
       paint.setColor(colors[currentColor++%8]);
       path.moveTo(northXStart, northYStart);
       path.lineTo(northXEnd, northYEnd);
       canvas.drawPath(path, paint);

       path.reset();
       paint.setColor(colors[currentColor++%8]);
       path.moveTo(notheastXStart, notheastYStart);
       path.lineTo(notheastXEnd, notheastYEnd);
       canvas.drawPath(path, paint);

       path.reset();
       paint.setColor(colors[currentColor++%8]);
       path.moveTo(eastXStart, eastYStart);
       path.lineTo(eastXEnd, eastYEnd);
       canvas.drawPath(path, paint);

       path.reset();
       paint.setColor(colors[currentColor++%8]);
       path.moveTo(southeastXStart, southeastYStart);
       path.lineTo(southeastXEnd, southeastYEnd);
       canvas.drawPath(path, paint);

       path.reset();
       paint.setColor(colors[currentColor++%8]);
       path.moveTo(southXStart, southYStart);
       path.lineTo(southXEnd, southYEnd);
       canvas.drawPath(path, paint);

       path.reset();
       paint.setColor(colors[currentColor++%8]);
       path.moveTo(southwestXStart, southwestYStart);
       path.lineTo(southwestXEnd, southwestYEnd);
       canvas.drawPath(path, paint);

       path.reset();
       paint.setColor(colors[currentColor++%8]);
       path.moveTo(westXStart, westYStart);
       path.lineTo(westXEnd, westYEnd);
       canvas.drawPath(path, paint);

   }
  1. 平时写代码的过程中,要注意对字符串的“+=”操作和截取操作都会创建出对象,在一些频繁被调用的方法中要避免去创建对象。
  2. 频繁的创建对象会导致jvm虚拟机进行频繁的GC操作,会导致内存抖动,程序出现卡顿和OOM。

相关文章

网友评论

    本文标题:借助profiler工具进行内存分析

    本文链接:https://www.haomeiwen.com/subject/sfxymhtx.html