什么是内存泄漏?
答:在程序开发中,当一个对象已经不需要再使用,本该被回收时,而另外一个正在使用的对象持有它的引用从而导致它不能被回收,这就导致本该被回收的对象不能被回收而停留在堆内存中,内存泄漏就产生了。
内存泄漏的危害?
答:它是造成应用程序OOM的主要原因之一。由于Android系统为每个应用程序分配的内存有限,当一个应用中产生的内存泄漏比较多时,就难免会导致应用所需要的内存超过这个系统分配的内存限额,这就造成了内存溢出而导致应用Crash。
内存泄漏的场景:
- Activity和View
- 单例模式
解决办法
:将静态单例中持有的Activity的Context改为Application的Context。
context.getApplicationContext(); - 线程
原因
:异步任务和Runnable都是一个匿名内部类,默认持有一个当前Activity的隐式引用, 如果Activity在销毁之前,任务还未完成, 那么将导致Activity的内存资源无法回收,造成内存泄漏。
解决办法
: 使用静态内部类 - 静态变量
- 非静态内部类创建静态实例
原因
:非静态内部类默认会持有外部类的引用,而又使用了该非静态内部类创建了一个静态的实例,该实例的生命周期和应用的一样长,这就导致了该静态实例一直会持有该Activity的引用,导致Activity的内存资源不能正常回收。
解决办法
: 将该内部类设为静态内部类或将该内部类抽取出来封装成一个单例,如果需要使用Context,使用ApplicationContext。
Handler:
原因:同非静态内部类创建静态实例, 那么当这个Activity退出时,消息队列中还有未处理的消息或者正在处理消息,而消息队列中的Message持有mHandler实例的引用,mHandler又持有Activity的引用,所以导致该Activity的内存资源无法及时回收,引发内存泄漏。
解决办法:
创建一个静态Handler内部类,然后对Handler持有的对象使用弱引用
使用mHandler.removeCallbacksAndMessages(null);是移除消息队列中所有消息和所有的Runnable。当然也可以使用mHandler.removeCallbacks();或mHandler.removeMessages();来移除指定的Runnable和Message。 - 未取消注册或回调
- Timer和TimerTask
- 集合中对象未清理
- 资源未关闭或释放
对于使用了BraodcastReceiver,ContentObserver,File,Cursor,Stream,Bitmap等资源的使用,应该在Activity销毁时及时关闭或者注销,否则这些资源将不会被回收,造成内存泄漏。 - 属性动画
原因
: 无限循环动画,如果在Activity中播放这类动画并且在onDestroy中没有去停止动画,那么这个动画将会一直播放下去,这时候Activity会被View所持有,从而导致Activity无法被释放。
解决办法
: 在Activity中onDestroy去调用objectAnimator.cancel()来停止动画。 - WebView
- 第三方库使用不当
对于EventBus,RxJava等一些第三开源框架的使用,若是在Activity销毁之前没有进行解除订阅将会导致内存泄漏。
什么是内存溢出 ?
指程序申请内存时,没有足够的内存供申请者使用,或者说,给了你一块存储int类型数据的存储空间,但是你却存储long类型的数据,那么结果就是内存不够用,此时就会报错OOM,即所谓的内存溢出。
内存泄漏的堆积最终会导致内存溢出
网友评论