前言
单例导致内存泄露
单例模式在 Android 开发中会经常用到,但是如果使用不当就会导致内存泄露。因为单例的静态
特性使得它的生命周期同应用的生命周期一样长,如果一个对象已经没有用处了,但是单例还持
有它的引用,那么在整个应用程序的生命周期它都不能正常被回收,从而导致内存泄露。
public class AppSettings {
private
static AppSettings sInstance;
private
Context mContext;
private
AppSettings(Context context) {
this.mContext = context;
}
public
static AppSettings getInstance(Context context) {
if
(sInstance
== null) {
sInstance
= new AppSettings(context);
}
return sInstance;
}
}
像上面代码中这样的单例,如果我们在调用 getInstance(Context context)方法的时候传入的 context 参数是 Activity、Service 等上下文,就会导致内存泄露。 以 Activity 为例,当我们启动一个 Activity,并调用 getInstance(Context context)方法去获取AppSettings 的单例,传入 Activity.this 作为 context,这样 AppSettings 类的单例 sInstance 就持有了 Activity 的引用,当我们退出 Activity 时,该 Activity 就没有用了,但是因为 sIntance作为静态单例(在应用程序的整个生命周期中存在)会继续持有这个 Activity 的引用,导致这个Activity 对象无法被回收释放,这就造成了内存泄露。
为了避免这样单例导致内存泄露,我们可以将 context 参数改为全局的上下文:
private AppSettings(Context context) {
this.mContext = context.getApplicationContext();
}
全局的上下文 Application Context 就是应用程序的上下文,和单例的生命周期一样长,这样就避免了内存泄漏。
单例模式对应应用程序的生命周期,所以我们在构造单例的时候尽量避免使用 Activity的上下文,而是使用 Application 的上下文。
总结
内存泄露在 Android 内存优化是一个比较重要的一个方面,很多时候程序中发生了内存泄露我们不一定就能注意到,所有在编码的过程要养成良好的习惯。总结下来只要做到构造单例的时候尽量别用 Activity 的引用这点就能避免该种情况的内存泄漏: