-
单例模式对象造成的内存泄漏
因为单例模式对象的静态特性使得单例的生命周期和应用的生命周期一样长,有时创建单例模式对象时需要Context对象,如果传入的是Activity的Context对象,那么当Activity生命周期结束时,该Activity的引用依然被单例模式对象持有,所以该Activity不会被回收,而单例模式对象的生命周期又是跟应用一样长,因此造成内存泄露。
-
非静态内部类创建静态实例造成的内存泄漏
我们如果在启动频繁的Activity中,一般会为了避免重复创建相同的数据资源,在Activity内部创建了一个非静态内部类的单例模式对象,每次启动Activity时都会使用该单例模式对象的数据,这样虽然避免了资源的重复创建。非静态内部类默认持有外部类的引用,并且使用了该非静态内部类创建了一个静态的实例,该实例的生命周期和应用的一样长,这样导致了该静态实例一直会持有该Activity的引用,导致Activity的内存资源不能正常回收。
-
Handler造成的内存泄漏
我们在处理网络任务或者封装一些请求回调等api一般会用Handler来处理。
首先在Activity里面这样定义一个私有的Handler对象并初始化
private Handler mHandler = new Handler(){...}
由于mHandler是Handler的非静态匿名内部类的实例,所以它持有外部类Activity的引用。当Activity产生消息时会用sendMessage()发送到消息队列(Message Queue)是在一个Looper线程中不断轮询利用dispatchMessage()发送消息给Handler的handleMessage()进行处理消息。如果这个Activity退出时消息队列中还有未处理的消息或者正在处理消息,而消息队列中的Message持有mHandler实例的引用,mHandler又持有Activity的引用,所以导致该Activity的内存资源无法及时回收,引发内存泄漏。
-
连接或资源未关闭
如果使用了BraodcastReceiver,ContentObserver,File,Cursor,Stream,Bitmap等或者HttpURLConnection,应该在Activityd销毁时在OnDestroy()函数及时关闭或者注销,否则这些资源或连接将不会被回收,造成内存泄漏。
-
内存泄漏的排查和解决——LeakCanary
LeakCanary是Square开源的一个内存泄露检测排查的库。使用如下:- 在build.gradle添加依赖
dependencies {
debugCompile 'com.squareup.leakcanary:leakcanary-android:1.5'
releaseCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.5'
testCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.5'
}
- 在Application的类中的onCreate()添加如下代码:
public class ExampleApplication extends Application {
@Override public void onCreate() {
super.onCreate();
if (LeakCanary.isInAnalyzerProcess(this)) {
// This process is dedicated to LeakCanary for heap analysis.
// You should not init your app in this process.
return;
}
LeakCanary.install(this);
// Normal app init code...
}
}
当在你debug应用程序时,如果应用存在内存泄漏,LeakCanary会自动显示一个通知告诉开发者哪里存在泄漏。