单例模式是我们项目中经常使用的一个设计模式,但是如果使用不当,也会引发内存泄漏。
例如: 下面这种常见的写法,传了一个Context 进去
import android.content.Context;
public class Utils {
private Context mContext;
private static Utils utils;
private Utils(Context mContext) {
this.mContext = mContext;
}
public static Utils getInstance(Context mContext) {
if (utils == null) {
synchronized (Utils.class) {
if (utils == null) {
utils = new Utils(mContext);
}
}
}
return utils;
}
}
当我们使用的时候:
public class MainActivity extends BaseActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Utils.getInstance(this);
}
}
我们先运行一下,并通过 Android studio 自带的内存检测工具测试一下当前的内存使用情况
注意:android studio 3.0 的内存测试工具 是 Profiler ,android studio 3.0 之前使用的是 anroid Monitor
这里我的android studio 的版本是3.0以上的
先看一下第一次运行时的内存占用情况
然后旋转一次屏幕之后
可以看到,内存使用大小有所上升。在多旋转几次
可以看到有明显的上升。
我们点击 一个向下的箭头按钮,查看分析日志
可以看到,当前存在多个 MainActivity 的实例。
然后我们手动 gc(箭头左边的 垃圾桶按钮),正常情况下,只会存在一个 MainActivity 实例,但是,我们多次gc后返现,仍然存在两个MainActivity 的实例,如图:
这就说明,已经产生了内存泄漏,GC 已经不能掌控这部分内存了。
原因:
首先,我们的单例模式使用的是 static 修饰的,我们知道,static 修饰的对象会一直存在内存中
我们在 MainActivity 的onCreat() 方法中 ,调用了 Utils.getInstance(this)。把ManActicity 传了进入,创建了 Utils 的实例。
当我们旋转屏幕的时候,MainActivity 会走 onDestory() 方法,但是 当前MainAcivity 被 Utils对象 持有引用,
并不会被销毁,然后 再次走onCreate() 方法,方法中 再次调用 Utils.getInstance(this),会把 新的MainActivity 对象传进去
但是: 当前 的Utils 实例并不为null ,条件判断走不进去,会直接返回 utils。
public static Utils getInstance(Context mContext) {
if (utils == null) {
synchronized (Utils.class) {
if (utils == null) {
utils = new Utils(mContext);
}
}
}
return utils;
}
所以产生内存泄漏。
解决:
只需要把当前类的上下文,改为application就行
此时 我们旋转屏幕,MainActivity 重写加载。