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

public class Utils {

    private static Utils sInstance;
    private Context mContext;

    private AppSettings(Context context) {
        this.mContext = context;
    }

    public static Utils getInstance(Context context) {
        if (sInstance == null) {
            sInstance = new Utils(context);
        }
        return sInstance;
    }
}

以上单例 context 参数如果传入的是 Activity,Service的上下文对象就会造成内存泄漏,因为静态单例sInstance对象生命周期与 Application 一样长,当 Activity或 Service 销毁时 Utils 还在引用 Activity 或 Service,导致 Activity,Service 不能被回收。

2.非静态内部类内存泄漏

非静态内部类默认持有外部类对象引用。生命周期与应用一样长,所以导致外部类销毁的时候内部类仍然引用外部类,导致外部类不能被回收。
解决方法:改成静态内部类.

典型场景:
//线程匿名内部类
new Thread(new Runnable() {
            @Override
            public void run() {
                // 模拟相应耗时逻辑
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();

new AsyncTask<Void, Void, Void>() {
            @Override
            protected Void doInBackground(Void... params) {
                // 模拟相应耗时逻辑
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                return null;
            }
        }.execute();
//线程写成静态内部类
private static class MyThread implements Runnable {
    public void run() {
        SystemClock.sleep(20000);
    }
}
//Handler造成的内存泄漏
public class DemoActivity extends Activity {
  private final Handler mLeakyHandler = new Handler() {
    @Override
    public void handleMessage(Message msg) {
      // ... 
    }
  }
}

由于消息队列持有 handler 引用,handler 又持有 activity 的引用,当消息队列中的消息还没有处理完,activity 就销毁,导致 activity引用仍被使用不能被回收。解决方法:使用静态内部类+弱引用(静态类不会引用 activity,通过弱引用来引用 activity 中的资源)

public static class MyHandler extends Handler {
    //声明一个弱引用对象
    WeakReference<MainActivity> mReference;

    MyHandler(MainActivity activity) {
        //在构造器中传入Activity,创建弱引用对象
        mReference = new WeakReference<MainActivity>(activity);
    }

    public void handleMessage(Message msg) {
        //在使用activity之前先判空处理
        if (mReference != null && mReference.get() != null) {
            mReference.get().text.setText("hello word");
        }
    }
}

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

3.静态变量导致内存泄露

静态变量的生命周期与应用一致,当变量被初始化后,它持有的引用到进程结束才会释放。要尽量少的使用静态变量,在适当时候设置 null。

4.未取消注册或回调导致内存泄露

如广播,EventBus注册,在 Activity 销毁后没有取消注册,activity 引用就会被一直持有。销毁时要取消注册。

5.资源对象未及时释放

如Cursor、Stream、Socket,Bitmap等在使用后要及时关闭。

6.集合中的对象未清理造成内存泄露

我们有时会用集合存储对象引用,当对象不用时没有清理集合导致集合越来越大,如果集合是静态的更会造成内存泄漏。要在适当时候clear集合,然后设置为 null。