android c 内存泄露,Android中常见的内存泄露及解决办法汇总

内存泄露就是指该被GC垃圾回收的,因为有另一个对象仍然在引用它,致使没法回收,形成内存泄露,过多的内存泄露会致使OOM。html

android中的内存泄露一般是Activity或者Fragment的泄露。下文分析以Activity展开,Fragment同理。java

1. 非静态内部类、匿名内部类

非静态内部类、匿名内部类 都会持有外部类的一个引用,若是有一个静态变量引用了非静态内部类或者匿名内部类,致使非静态内部类或者匿名内部类的生命周期比外部类(Activity)长,就会致使外部类在该被回收的时候,没法被回收掉,引发内存泄露, 除非外部类被卸载(JVM自带的类加载器所加载的类,在虚拟机的生命周期中,始终不会被卸载,除非使用自定义的类加载器,感兴趣的同窗能够研究一下)。android

解决办法:

将非静态内部类、匿名内部类 改为静态内部类,或者直接抽离成一个外部类。

若是在静态内部类中,须要引用外部类对象,那么能够将这个引用封装在一个WeakReference中。以下面代码所示:

01689dbe9520123e97220e29d9b4544c.png程序员

2. 静态的View

有时,当一个Activity常常启动,可是对应的View读取很是耗时,咱们能够经过静态View变量来保持对该Activity的rootView引用。这样就能够不用每次启动Activity都去读取并渲染View了。这确实是一个提升Activity启动速度的好方法!可是要注意,一旦View attach到咱们的Window上,就会持有一个Context(即Activity)的引用。而咱们的View有事一个静态变量,因此致使Activity不被回收。web

解决办法:

在使用静态View时,须要确保在资源回收时,将静态View detach掉。数据库

3. Handler

咱们知道,主线程的Looper对象不断从消息队列中取出消息,而后再交给Handler处理。若是在Activity中定义Handler对象,那么Handler确定是持有Activty的引用。而每一个Message对象是持有Handler的引用的(Message对象的target属性持有Handler引用),从而致使Message间接引用到了Activity。若是在Activty destroy以后,消息队列中还有Message对象,Activty是不会被回收的。固然了,若是消息正在准备(处于延时入队期间)放入到消息队列中也是同样的。缓存

解决办法:

将Handler放入单独的类或者将Handler放入到静态内部类中(静态内部类不会持有外部类的引用)。若是想要在handler内部去调用所在的外部类Activity,能够在handler内部使用弱引用的方式指向所在Activity,这样不会致使内存泄漏。

或者在onDestory时,调用相应的方法移除回调和删除消息。

9bee81f4fd12d79ee83b2cec3baae622.png架构

4. 监听器(各类须要注册的Listener,Watcher等)

当咱们须要使用系统服务时,好比执行某些后台任务、为硬件访问提供接口等等系统服务。咱们须要把本身注册到服务的监听器中。然而,这会让服务持有 activity 的引用,若是程序员忘记在 activity 销毁时取消注册,那就会致使 activity 泄漏了。

例如:EditText的一个addTextChangeListener,若是在回调方法里有耗时操做,可能会形成内存泄露。

34de2282f972d7a4201d86c68c2848f7.pngsvg

解决办法:

在onDestory时,取消注册,editText.removeTextChangedListener函数

5. 资源对象没关闭形成内存泄漏

当咱们打开资源时,通常都会使用缓存。好比读写文件资源、打开数据库资源、使用Bitmap资源等等。当咱们再也不使用时,应该关闭它们,使得缓存内存区域及时回收。虽然有些对象,若是咱们不去关闭,它本身在finalize()函数中会自行关闭。可是这得等到GC回收时才关闭,这样会致使缓存驻留一段时间。若是咱们频繁的打开资源,内存泄漏带来的影响就比较明显了。

解决办法:

及时关闭资源

6. 属性动画

在使用ValueAnimator或者ObjectAnimator时,若是没有及时作cancel取消动画,就可能形成内存泄露。

由于在cancel方法里,最后调用了endAnimation(); ,在endAnimation里,有个AnimationHandler的单例,会持有属性动画对象的引用,以下代码所示;

1df37a8cac71fc5cb5401cae7e6facba.png

解决办法:

在在onDestory时,调用动画的cancel方法

7. RxJava

在使用RxJava时,若是在发布了一个订阅后,因为没有及时取消,致使Activity/Fragment没法销毁,致使的内存泄露

解决办法:

参考Uber出品的一个开源库AutoDispose的使用,能够参考下文:

Android架构中添加AutoDispose解决RxJava内存泄漏

8. WebView

在android 5.1及以上版本的代码中,WebView可能会存在内存泄露,

缘由能够参考这篇文章:Android 5.1 WebView内存泄漏问题及解决

解决办法:

在销毁webview前必定要onDetachedFromWindow,咱们先将webview从它的父view中移除再调用destroy方法,代码以下:

dac466155725390a1163339cf03642b6.png

9. 其余的系统控件以及自定义View

在 Android Lollipop 以前使用 AlertDialog 可能会致使内存泄漏

参考:一个内存泄漏引起的血案

Dialog和DialogFragment在Android5.0如下的内存泄漏

参考:解决Android5.0如下Dialog引发的内存泄漏

View的post方法致使的内存泄漏分析

view中有线程或者动画 要及时中止

这是为了防止内存泄漏,能够在onDetachedFromWindow方法中结束,这个方法回调的时机是 当View的Activity退出或者当前View被移除的时候 会调用 这时候是结束动画或者线程的好时机 另外还有一个对应的方法 onAttachedToWindow 这个方法调用的时机是在包含View的Activity启动时 回调 回调在onDraw方法 以前

10. 不必定非要使用弱引用才行

如避免AsyncTask内存泄漏的简单例子:

050b610a50d0f5503294258ca5b12824.png

这里是AsyncTask:

64da1f2cc44b7d37ed5e619678d1e3a3.png

固然这个例子很是基础,可是我认为做为另外一种解决方案的演示来讲足够了。

这里是另外一个使用RxJava实现的简单例子,咱们仍然没有使用弱引用。

7eddd6929ee0db368c18551ea9a5e5eb.png

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值