目录
简单描述:没有用的对象无法回收的现象就是内存泄露
如果程序发生了内存泄露,则会带来以下这些问题
- 应用可用的内存减少,增加了堆内存的压力
- 降低了应用的性能,比如会触发更频繁的 GC
- 严重的时候可能会导致内存溢出错误,即 OOM Error
OOM 发生很有可能是内存泄露导致的,但并非所有的 OOM 都是由内存泄露引起的,内存泄露也并不一定引起 OOM。
一、Java 的内存管理和引用类型
二、Android 中内存泄露的常见场景 & 解决方案
1、单例模式强引用Context造成的内存泄露
过多的单例会让内存占用过多,而且单例模式由于其 静态特性,其生命周期 = 应用程序的生命周期,不正确地使用单例模式也会造成内存泄露。
单例模式
public class SingleInstanceTest {
private static SingleInstanceTest sInstance;
private Context mContext;
private SingleInstanceTest(Context context){
this.mContext = context;
}
public static SingleInstanceTest newInstance(Context context){
if(sInstance == null){
sInstance = new SingleInstanceTest(context);
}
return sInstance;
}
}
上面是一个比较简单的单例模式用法,需要外部传入一个 Context 来获取该类的实例,如果此时传入的 Context 是 Activity 的话,此时单例就有持有该 Activity 的强引用(直到整个应用生命周期结束)。这样的话,即使该 Activity 退出,该 Activity 的内存也不会被回收,这样就造成了内存泄露,特别是一些比较大的 Activity,甚至还会导致 OOM(Out Of Memory)。
解决方法: 使用 getApplicationContext() 单例模式引用的对象的生命周期 = 应用生命周期
public class SingleInstanceTest {
private static SingleInstanceTest sInstance;
private Context mContext;
private SingleInstanceTest(Context context){
this.mContext = context.getApplicationContext();
}
public static SingleInstanceTest newInstance(Context context){
if(sInstance == null){
sInstance = new SingleInstanceTest(context);
}
return sInstance;
}
}
2、普通类强引用Context造成的内存泄露
public class Sample {
private Context mContext;
public Sample(Context context){
this.mContext = context;
}
public Context getContext() {
return mContext;
}
}
// 外部调用
Sample sample = new Sample(MainActivity.this);
解决方法: 使用 弱引用 WeakReference
public class Sample {
private WeakReference<Context> mWeakReference;
public Sample(Context context){
this.mWeakReference = new WeakReference<>(context);
}
public Context getContext() {
if(mWeakReference.get() != null){
return mWeakReference.get();
}
return null;
}
}
被弱引用关联的对象只能存活到下一次垃圾回收之前,也就是说即使 Sample 持有 Activity 的引用,但由于 GC 会帮我们回收相关的引用,被销毁的 Activity 也会被回收内存,这样我们就不用担心会发生内存泄露了。
3、非静态内部类 / 匿名类
4、静态集合类 / 静态变量 / static
static List<Object> objectList = new ArrayList<>();
for (int i = 0; i < 10; i++) {
Object obj = new Object();
objectList.add(obj);
obj = null;
}
静态变量的生命周期和应用程序一致,而且他们所引用的对象 Object 也不能释放,这样便造成了内存泄露。
解决方法:在集合元素使用之后从集合中删除,等所有元素都使用完之后,将集合置空。
objectList.clear();
objectList = null;
三、内存泄露排查工具
1、Android Lint
Lint 是 Android Studio 提供的 代码扫描分析工具,它可以帮助我们发现代码机构 / 质量问题,同时提供一些解决方案,检测内存泄露当然也不在话下,使用也是非常的简单,可以参考下这篇文章:Android 性能优化:使用 Lint 优化代码、去除多余资源
2、leakcanary
LeakCanary 是 Square 公司开源的「Android 和 Java 的内存泄漏检测库」,Square 出品,必属精品,功能很强大,使用也很简单。建议直接看 Github 上的说明:leakcanary,也可以参考这篇文章:Android内存优化(六)LeakCanary使用详解