第十二章作业 MemoryBugs-master项目优化笔记

作业要求:

下载bug项目:https://github.com/lzyzsd/MemoryBugs,请注意配合使用MemoryMonitor, AllocationTracker以及HeapDump,LeakCanary等工具来查找潜在的内存问题,并尝试解决。

要求:写一篇博客,将分析解决过程描述清楚,提交作业时附上链接地址,并上传改好的项目文件。

 

首先下载作业要求的项目,导入Android studio,由于该项目使用的gradle版本是2.0,版本比较低打不开。可以修改项目的的全局gradle文件,把版本改到最新版,修改方法如下:

    dependencies {
        classpath 'com.android.tools.build:gradle:2.1.2'

        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files
    }

打开项目以后运行在模拟器,看到如下界面:

 

有两个按钮,分别是"StartActivityB"和"StartAllocation",

经过分析第一个按钮主要运行的是这段代码:

    private void startB() {
        finish();
        startActivity(new Intent(this, ActivityB.class));
        mHandler.postDelayed(new Runnable() {
            @Override
            public void run() {
                System.out.println("post delayed may leak");
            }
        }, 5000);
        Toast.makeText(this, "请注意查看通知栏LeakMemory", Toast.LENGTH_SHORT).show();
    }

代码意义关闭当前的Activity页面,跳转至另一个Activity,同时启动一个延时Handler子线程,打印一段log。

 

第二个按钮的主要代码是:

    private void startAllocationLargeNumbersOfObjects() {
        Toast.makeText(this, "请注意查看MemoryMonitor 以及AllocationTracker", Toast.LENGTH_SHORT).show();
        for (int i = 0; i < 10000; i++) {
            Rect rect = new Rect(0, 0, 100, 100);
            System.out.println("-------: " + rect.width());
        }
    }

意义为一个toast菜单和一段循环代码,用以创建10000个Rect对象。

 

好了,下面开始分析存在的内存问题:

一、使用Memory Monitor进行分析。

首先打开项目,启动MemoryMonitor进行检测,检测图如下:

首次打开以后

 

可以看到蓝色的部分表示已分配的内存,淡蓝色的部分表示未被使用的内存。蓝色部分稳定在2.75MB,点击第二个按钮以后的图形如下:

 

可以看到点击以后出现了好几次内存比较明显的起伏波动,说明程序的内存使用是有问题的,下面继续分析。

 

二、Allocation Tracker分析

 通过这个工具的分析就可以进一步定位出问题的位置到底在哪儿。

通过这张分析图可以看到,在mainactivity当中,新建了大量的rect和StringBuilder对象,导致出现了大量的内存占用。

找到了问题所在,就是因为第二个按钮执行的代码通过一个for循环,创建了一万个rect对象引起的。现在就来解决这个问题,代码如下:

    private void startAllocationLargeNumbersOfObjects() {
        Toast.makeText(this, "请注意查看MemoryMonitor 以及AllocationTracker", Toast.LENGTH_SHORT).show();
        Rect rect = null;
        for (int i = 0; i < 10000; i++) {
            if (rect==null) {
                rect = new Rect(0, 0, 100, 100);
                System.out.println("-------: " + rect.width());
            }
        }
    }

通过在for循环里面加了一个if判断来解决了这个问题,如果对象已经存在,则不会再次创建,这样就只会创建一次对象。

 

三、LeakCanary分析

使用这种工具来分析,需要在gradle里面做一下依赖,这里就不再多说,下面看运行以后的提示:

根据这个页面的提示,MainActivity中的一个静态sTextView引用了这个页面的context,导致了内存泄露。

查看了相关代码发现sTextView是一个静态对象,这应该就是一个静态对象引用了外面的非静态类引起的内存泄露。

把这个对象的静态修饰符删掉即可解决问题。

private static TextView sTextView;//修改前

private TextView sTextView;//修改后

 

 解决了内存问题以后,再来对视图进行优化。

首先在手机开发者选项当中打开“显示GPU过度绘制”选项,然后打开项目APP,效果如下:

 首先对自定义的控件进行优化,分析一下代码:

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

        RectF rect = new RectF(0, 0, 100, 100);
        Paint paint = new Paint();
        paint.setColor(Color.RED);
        paint.setStrokeWidth(4);
        canvas.drawArc(rect, 0, 180, true, paint);
    }

可以看到,在onDraw方法当中创建了两个新对象,由于onDraw方法是会反复刷新调用的,在这里创建对象,就会造成过度绘制,所以我把这两个创建对象的操作移动到构造方法里面进行,整个的代码如下:

 1 public class MyView extends View {
 2 
 3     private RectF mRect = null;
 4     private Paint mPaint = null;
 5 
 6     public MyView(Context context) {
 7         super(context);
 8         init();
 9     }
10 
11     public MyView(Context context, AttributeSet attrs) {
12         super(context, attrs);
13         init();
14     }
15 
16     public MyView(Context context, AttributeSet attrs, int defStyleAttr) {
17         super(context, attrs, defStyleAttr);
18         init();
19     }
20 
21     private void init() {
22         if (mPaint == null || mRect == null) {
23             mRect = new RectF(0, 0, 100, 100);
24             mPaint = new Paint();
25         }
26     }
27 
28     @TargetApi(Build.VERSION_CODES.LOLLIPOP)
29     public MyView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
30         super(context, attrs, defStyleAttr, defStyleRes);
31     }
32 
33     @Override
34     protected void onDraw(Canvas canvas) {
35         super.onDraw(canvas);
36         mPaint.setColor(Color.RED);
37         mPaint.setStrokeWidth(4);
38         canvas.drawArc(mRect, 0, 180, true, mPaint);
39     }
40 }

 

 

大致上针对这个小demo的优化就做完了,当然肯定还有很多不足的地方,希望同学们多多指教,指出不足。

转载于:https://www.cnblogs.com/xxxlu/p/5698992.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值