内存泄漏:所谓内存泄漏就是指本该回收的内存还驻留在内存中
1.1 Android内存回收机制:Android虚拟机采用的是根节点搜索算法枚举根节点判定是否是垃圾,虚拟机会从GC Roots 开始遍历,如果一个节点找不到一条到达GC Roots的路线,也就是说没有和GC Roots相连,那么就证明该引用无效,可以被回收,内存泄漏就是存在一些不好的调用导致一些无用的对象和GC Roots相连,无法回收。
1.2 Andorid中内存泄漏大致原因
1.2.1 static变量引起的内存泄漏:因为static变量的生命周期是在类加载开始到类加载结束,也就是说static变量是在程序进程死亡时才释放,如果在static变量中引用了Activity,那么这个Activity由于被引用,便会和static变量的生命周期一样,一直无法释放,造成内存泄漏
** 解决方案:在Activity被静态引用时,使用getApplicationContext,因为Application的生命周期是从程序开始到程序结束,和static变量的生命周期一样;如果在某些Dialog或者一些单例里面用到了Activity,可以在这些类里面写一个release方法用于释放Activity引用,比如给Dialog设置OnDismissListener()在里面释放Activity引用
1.2.2 线程造成的内存泄漏:例如在Activity里面线程执行时间很长,即使Activity退出该线程仍然会执行,因为线程或者Runnable是内部类,因此持有外部类(Activity)的实例,从而导致Activity无法释放
** 解决方案:1)合理安排线程执行的时间,控制线程在Activity结束前结束(在run方法里面设置代码执行开关,即flag,一般长时间执行的线程都是循环执行一些操作)
2)将内部类改为静态内部类,并使用弱引用WeakReference来保存Activity实例,因为弱引用只要GC发现了就会回收它,因此可尽快回收(静态内部类不依赖外部类)
1.2.3 资源未被及时关闭造成的内存泄漏:比如数据库Cursor没有及时close,读写文件的时候IO流没有及时close,MediaScannerConnection没有调用disConnect等
** 解决方案:及时关闭资源
1.2.4 Handler的使用造成的内存泄漏:由于在Handler的使用中,Handler会发送Message对象到MessageQueue中,然后Looper会轮询MessageQueue然后取出Message执行,但是如果一个Message长时间没有被取出执行,那么由于Message中有Handler的引用,而Handler一般来说是内部类对象,Message引用Handler,Handler引用Activity,这样就导致Activity无法被回收
** 解决方案:使用静态内部类+弱引用方式解决,或者在Activity结束清空Handler的消息队列和一些回调,调用Handler.removeCallbackAndMessages(null)
1.2.5 广播监听注册之后没有解注册
** 解决方案:比如使用EventBus后在onDestroy里面unRegister
如果有泄漏的Activity的话这里会列出具体的Activity名,然后左边就是该Activity引用的地方,可以自己分析,当然也可以借助LeakCanary来分析
3.使用LeakCanary
链接:https://github.com/square/leakcanary
具体使用:1.添加Gradle配置
2.实现一个全局的RefWatcher获取方法,比如在Application里面构造一个
public class MainApplication extends Application {
private RefWatcher mRefWatcher;
@Override
public void onCreate() {
super.onCreate();
mRefWatcher = initLeakCanary();
}
private RefWatcher initLeakCanary() {
if (LeakCanary.isInAnalyzerProcess(this)) {
return RefWatcher.DISABLED;
}
return LeakCanary.install(this);
}
public static RefWatcher getRefWatcher(Context context) {
MainApplication application = (MainApplication) context.getApplicationContext();
return application.mRefWatcher;
}
}
3.在BaseActivity的onDestroy里面监听,调用MainApplication.getRefWatcher(this).watch(this);
4.运行安装app后操作自己的app,这个时候LeakCanary就会自动检测内存泄漏并会自动给出分析结果