由于我能力有限,所以不敢称这是博客(博客一般都具有分享性),这只是笔记,所以在写的过程中我也会尽量描述的清楚些,希望对你有所帮助。当做个人历程而已。
内存泄露的根本原因:生命周期长的持有了生命周期短的引用。下面就介绍下,我们平时开发中常见的泄露例子。
补充上篇知识:内存泄露是说,本该被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工具:点击下载