什么是内存泄露
内存泄漏的发生原因本质上是因为生命周期较长的对象去引用生命周期较短的对象,导致生命周期短的对象无法被GC及时回收掉,从而导致被占用的内存无法被释放,如果程序长期运行最终可能会导致OOM内存溢出。
什么情况下容易发生内存泄漏?
导致内存泄漏的原因有很多以下列举几种常见情况。
一、Handler 引起的内存泄漏。
我们知道,Handler、Message、MessageQueue是相互关联在一起的,Handler通过发送消息Message与主线程进行交互,如果Handler发送的消息Message尚未被处理,该Message及发送它的Handler对象将被MessageQueue一直持有,这样就可能会导致Handler无法被回收,从而导致内存泄漏。
举个例子:
AActivity代码中有一个延迟1秒执行的消息Message,当界面从AActivity跳转到BActivity时,AActivity自动进入后台,此时如果系统资源紧张(或者打开设置里面的“不保留活动”选项),AActivity将会被finish。但问题来了,假设AActivity的Handler对象mHandler为非静态匿名内部类对象,它会自动持有外部类AActivity的引用,从而导致SecondActivity无法被回收,造成内存泄漏。
解决办法:
将Handler声明为静态内部类,就不会持有外部类SecondActivity的引用,其生命周期就和外部类无关,如果Handler里面需要context的话,可以通过弱引用方式引用外部类,或者直接在Activity的onDestroy中将Handler对象销毁。
二、Bitmap没有调用recycle()
Bitmap对象在确认不使用时,我们应该先调用recycle()释放内存,然后在设置为null,否则会导致内存泄漏。
解决办法:
在Acrivity或Fragment处调用recycle()。
三、集合中对象没有清理造成的内存泄漏
我们经常把一些对象的引用加入到集合中,但我们不需要改对象时,并没有把它的引用从集合中清理掉,这样这个集合就会越来越大。如果这个集合是static,就会导致集合内的资源一直占用内存无法被清理。
解决办法:
当集合资源无用之后将其置空。
四、资源对象没关闭造成的内存泄漏
资源性对象比如(Cursor,File文件等)往往都用了一些缓冲,我们在不使用的时候,应该及时关闭它们,以便它们的缓冲及时回收内存。而不是等待GC来处理。
五、注册没有取消造成的内存泄漏
这种Android内存泄漏比Java的内存泄漏还要严重,因为其他一些Android程序可能引用系统的Android程序的对象(如注册机制)。即使Android程序已经结束,但是别的应用程序仍然还有对Android程序的某个对象的引用,也会造成内存泄漏。
解决方法:
1.使用ApplicationContext代替ActivityContext;
2.在Activity执行onDestory时,调用反注册;
检测内存泄漏的方法
LeakCanary 工具
官方地址如下:https://github.com/square/leakcanary/LeakCanary需要在项目代码中集成。当内存泄漏发生时,LeakCanary 会弹窗提示并生成对应的堆存储信息记录。
Android Profiler分析器
打开Android Studio,编译代码,在模拟器或者真机上运行App,然后点击以下图标,进入如下界面
该方式可以直观的观察在程序运行期间产生的内存波动并且可以明确列出所有产生内存消耗的对象以及内存分配情况,需要一些经验才能有效使用,