常见的安卓中的内存泄漏总结
Android的内存泄露(Memory Leak):
进程中某些对象已经没有使用价值了,但是他们却还可以直接或者间接地被引用到GC Root导致无法回收。当内存泄露过多的时候,再加上应用本身占用的内存,日积月累最终就会导致内存溢出OOM.
内存溢出(OOM):
当应用占用的heap资源超过了Dalvik虚拟机分配的内存就会内存溢出。比如:加载大图片等。
1.静态变量引起的内存泄露
当调用getInstance时,如果传入的context是Activity的context。只要这个单利没有被释放,那么这个Activity也不会被释放一直到进程退出才会释放。public class MyUtil {
private static MyUtil instance;
private Context context;
private MyUtil(Context context){
this.context = context;
}
public static MyUtil getInstance(Context mContext){
if(instance == null){
instance = new MyUtil(mContext);
}
return instance;
}
2.非静态内部类引起内存泄露
(包括匿名内部类)错误的示范:
public void loadData(){
//隐式持有MainActivity实例。MainActivity.this.a
new Thread(new Runnable() {@Override
public void run() {
while(true){
try {
//int b=a;
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}}}}).start();
}
解决方案:
将非静态内部类修改为静态内部类。(静态内部类不会隐式持有外部类)
当使用软引用或者弱引用的时候,MainActivity难道很容易或者可以被GC回收吗?
GC回收的机制是什么?当MainActivity不被任何的对象引用。
虽然Handler里面用的是软引用/弱引用,但是并不意味着不存在其他的对象引用该MainActivity。
我连MainActivity都被回收了,那Handler就有问题了。
{
mHandler.sendEmptyMessage(0);
mHandler.sendMessageAtTime(msg,10000);//atTime
}
//activity onDestroy把timer.cancel掉然后赋空
//错误的示范:
// mHandler是匿名内部类的实例,会引用外部对象MainActivity.this。如果Handler在Activity退出的时候,
它可能还活着,这时候就会一直持有Activity。
private Handler mHandler = new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what){
case 0:
//加载数据
break;
}
}
};
//解决方案:
private static class MyHandler extends Handler{
private MainActivity mainActivity;//直接持有了一个外部类的强引用,会内存泄露
//设置软引用保存,当内存一发生GC的时候就会回收。
private WeakReference<MainActivity> mainActivity; public MyHandler(MainActivity mainActivity) { this.mainActivity = new WeakReference<MainActivity>(mainActivity); } @Override public void handleMessage (Message msg){ super.handleMessage(msg); MainActivity main = mainActivity.get(); if (main == null || main.isFinishing()) { return; } switch (msg.what) { case 0: //加载数据 MainActivity.this.a; int b = main.a; break; } } };
3.不需要用的监听未移除会发生内存泄露
譬如:// tv.setOnClickListener();//监听执行完回收对象
//add监听,放到集合里面
tv.getViewTreeObserver().addOnWindowFocusChangeListener(new ViewTreeObserver.OnWindowFocusChangeListener() {
@Override
public void onWindowFocusChanged(boolean b) {
//监听view的加载,view加载出来的时候,计算他的宽高等。
//计算完要移除这个监听
tv.getViewTreeObserver().removeOnWindowFocusChangeListener(this);
}
});
譬如:
SensorManager sensorManager = getSystemService(SENSOR_SERVICE);
Sensor sensor = sensorManager.getDefaultSensor(Sensor.TYPE_ALL);sensorManager.registerListener(this,sensor,SensorManager.SENSOR_DELAY_FASTEST);
//不需要用的时候记得移除监听
sensorManager.unregisterListener(listener);
譬如:
自定义布局中的监听器:
public class MyView extends View{
public MyView(Context context){
super(context);
init();
}
//错误写法
// public MyView(Context context, AttributeSet attrs, MyListener myListener) {
// super(context, attrs);
// this.myListener = myListener;
// }
public interface MyListener{
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("有被调用");
}
};
}
public class ListenerCollector {
/**
* WeakHashMap,此种Map的特点是,当除了自身有对key的引用外,此key没有其他引用那么此map会自动丢弃此值
* 例如:int a = 1;
* Map weakmap = new WeakHashMap();
* weakmap.put(a, "aaa");
* a = null
* //此时weakmap里面的a会被丢弃。
*/
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();
}
}
调用
@Override
protected void onStop() {
super.onStop();
ListenerCollector.clearListeners();
}
4.无限循环动画
没有在onDestroy中停止动画,否则Activity就会变成泄露对象。
没有在onDestroy中停止动画,否则Activity就会变成泄露对象。比如:轮播图效果等。
5.资源未关闭引起的内存泄露情况
比如:BroadCastReceiver、Cursor、Bitmap、IO流、自定义属性attributeattr.recycle()回收。
当不需要使用的时候,要记得及时释放资源。否则就会内存泄露。
相关参考博文:
http://www.cnblogs.com/shaweng/archive/2012/06/29/2570413.html
http://blog.youkuaiyun.com/soiol/article/details/52486871