Android造成内存泄漏原因及解决方案

开发app中对内存的使用,一定是大家最关心的问题之一,因为内存的使用直接影响到app的性能。

内存使用中内存泄漏是开发Android应用中常见的,Android中可以使用LeakCanary来检测内存泄漏。

 

那么什么是内存泄漏?

内存泄漏简单解释就是:完全无用的对象,无法被被GC回收的现象就是内存泄漏。

 

内存泄漏会造成什么问题呢?

每个app可分配的内存是有限的,内存泄漏就会占有一块内存,过多的内存泄漏就会导致内存超出app可用的内存,导致内存溢出,app就奔溃了(引发Out Of Memory)。

 

接下来我们带着三个问题来分析下内存泄漏:

1.经常会出现内存泄漏的地方有哪些?

2.为什么会出现?

3.如何避免内存泄漏?

 

一.单例模式造成的内存泄漏:

public class Signleton {
    private static Signleton mSignleton;
    private Context mContext;
    private Signleton(Context context){
        this.mContext = context;
    }
    public static Signleton getInstance(Context context){
        if (mSignleton == null){
            mSignleton = new Signleton(context);
        }

        return mSignleton;
    }
}

这里为什么会出现内存泄漏呢?

     因为单例模式的生命周期和应用程序是一样长的,所以当我们在一个activity中调用这个单例,传入activity作为context,单例就持有了这个activity的引用,而当我们退出这个activity时,由于单例的生命周期是同应用程序一样长,所以这个单例还持有activity的引用,这个activity对象就不会被回收,这时就造成了内存泄漏。

如何解决:

private Signleton(Context context){
    this.context = context.getApplicationContext();
}

这里我们改成不管传入的context是activity还是其他的都转换为整个应用程序的context,这样生命周期就和单例一样长,就避免了内存泄漏。

 

二.非静态内部类造成的内存泄漏:  

private final String TAG = "DemoActivity";
private static Interior mInterior;
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main2);
    if (mInterior == null){
        mInterior = new Interior();
    }
}
class Interior{}

这里为什么会出现内存泄漏呢?

这个activity中有一个非静态内部类,因为非静态内部类中隐式持有外部类的引用,所以内部类Interior中就持有activity的引用,

例子中静态变量mInterior的生命周期是和应用程序一样长的,而该静态变量中又持有activity的引用,所以到activity销毁时,回收activity的时候无法被回收,就出现了内存泄漏。

如何解决:

static class Interior{

}

把该非静态内部类改成静态内部类就可以了(因为静态内部类不会持有外部的引用)。

 

三.Handler造成的内存泄漏:

private void toHandler(){
    mHandler.postDelayed(new Runnable() {
        @Override
        public void run() {
            tvTitle.setText("hello");
        }
    },1000);
}

这里为什么会出现内存泄漏呢?

这段代码中有两个方面会造成内存泄漏:

1.Runnable是匿名内部类,持有Activity的 TextView会造成内存泄漏。

2.TextView持有Activity 的强引用,这样也会造成内存泄漏。

因为handler的消息机制,当Activity销毁,handler中还有为处理的Message时就会持有activity的引用从而导致无法被回收,出现内存泄漏。

如何解决:

方法1:改成静态内部类+弱引用

private static class DemoRunnable implements Runnable{
    private WeakReference wTextView;
    protected DemoRunnable(TextView textView){
        wTextView = new WeakReference(textView);
    }
    @Override
    public void run() {
        wTextView.get().setText("hello");
    }

}

方法2:在Activity的onDestory中移除mHandler的所有Message

@Override
protected void onDestroy() {
    super.onDestroy();
    mHandler.removeCallbacksAndMessages(null);
}

四.线程造成的内存泄漏:

线程的内存泄漏同Handler一样也是匿名内部类Runnable造成的,解决方式同handler方法1一样。

五.资源未关闭造成的内存泄漏:

主要使用的资源:

1.BraodcastReceiver

2.ContentObserver

3.File

4.Cursor

5.Stream

6.Bitmap

这些资源的使用都需要在Activity销毁时及时关闭或者注销,否则这些资源将不会被回收,从而造成内存泄漏。

你可能感兴趣的:(android,BUG,android应用开发,Android性能优化)