Android性能优化篇(二),内存泄露的举例分析

由于我能力有限,所以不敢称这是博客(博客一般都具有分享性),这只是笔记,所以在写的过程中我也会尽量描述的清楚些,希望对你有所帮助。当做个人历程而已。

内存泄露的根本原因:生命周期长的持有了生命周期短的引用。下面就介绍下,我们平时开发中常见的泄露例子。

补充上篇知识:内存泄露是说,本该被GC回收的内存缺回收不了。而内存溢出是说,内存不够,比如Bitmap太大了,或者内存泄露的太多了,导致内存不足。

1、单例模式


    public class CommUtil {
        private static CommUtil instance;
        private Context context;
        private CommUtil(Context context){
            this.context = context;
        }

        public static CommUtil getInstance(Context context){
            if(instance == null){
                synchronized (CommUtil.class) {
                    instance = new CommUtil(context);
                }
            }
            return instance;
        }

    }

这是个典型的单例,在mainactivity中调用getInstatance(this),就会产生内存泄露。

分析:当屏幕发生旋转的时候,再次调用getInstatance(this)的时候,instance并不为空,所以CommUtil里面持有的还是上一个content。

解决方案:在mainactivity中调用getInstatance(getApplication)。因为app的整个上下文就只有一个。

2、观察者模式

自定义View中存在一个监听,这个在开发中也是非常常见的

首先创建一个集合类,WeakHashMap这是个集合弱引用,当key为null时,就会释放value

<pre name="code" class="java">WeakHashMap
public class ListenerCollector { static private WeakHashMap<View,MyView.MyListener> sListener = new WeakHashMap<>(); public void addsListener(View view, MyView.MyListener listener){ sListener.put(view,listener);}}

 在看下View类:在初始化的时候就把listener传进,因为比如像onCLickListener也是在初始化就有了 

public class MyView extends View{
    public  MyView(Context context){
        super(context);
        init();
    }

    public interface MyListener{
        public void myListenerCallback();
    }

    private void init(){
        ListenerCollector collector = new ListenerCollector();
        collector.setsListener(this,myListener);
    }

    private MyListener myListener = new MyListener() {
        @Override
        public void myListenerCallback() {
            System.out.print("有被调用");
        }
    };

}

然后在mainActivity中调用这个方法:

        MyView myView = new MyView(this);
        setContentView(myView);

泄露分析:运行程序,调用init(),就把view和listener放在集合里,退出activity,由于集合是static的,所以里面还会持有view的引用

解决方案:在ListenerCollector类中,添加一个静态方法,然后在activity的deStroy()方法中调用即可,代码如下

public class ListenerCollector {
    static private WeakHashMap<View,MyView.MyListener> sListener = new WeakHashMap<>();
    public void setsListener(View view, MyView.MyListener listener){ sListener.put(view,listener);}
    public static void clearListeners(){
        //移除所有监听。
        sListener.clear();
    };
}

此篇写到这里。关于检查泄露工具有,AS中自带的Monitor,还有MAT工具,不知道的就去百度下怎么用,这里我就不说了。下图是Android自带的检测工具


第一个:这个实例的总个数,第二个,实例在堆内存中的总个数,第三个,一个实例做占用的大小,第四个,这个实例的全部占用的总大小,第五个,GC干掉这个实例所释放的内存,为什么都要比Shallow大呢,因为一个实例也要可能被其他实例引用。

例外本人提供了MAT工具:点击下载

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值