美文网首页
Android内存泄漏

Android内存泄漏

作者: VitaAin | 来源:发表于2019-06-12 22:24 被阅读0次

    内存泄露就是指该被GC垃圾回收的,由于有另外一个对象仍然在引用它,导致无法回收,造成内存泄露,过多的内存泄露会导致OOM。

    一、原因及优化

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

    非静态内部类、匿名内部类 都会持有外部类的一个引用,如果有一个静态变量引用了非静态内部类或者匿名内部类,导致非静态内部类或者匿名内部类的生命周期比外部类(Activity)长,就会导致外部类在该被回收的时候,无法被回收掉,引起内存泄露,除非外部类被卸载(JVM自带的类加载器所加载的类,在虚拟机的生命周期中,始终不会被卸载,除非使用自定义的类加载器)。

    优化:
    • 将非静态内部类、匿名内部类 改成静态内部类,或者直接抽离成一个外部类。
    • 如果在静态内部类中,需要引用外部类对象,那么可以将这个引用封装在一个WeakReference中。

    2 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时,调用相应的remove方法移除回调和删除消息。

    弱引用相关请移步:Android强引用、弱引用、软引用

    3 静态的View

    有时,当一个Activity经常启动,但是对应的View读取非常耗时,可以通过静态View变量来保持对该Activity的rootView引用。这样就可以不用每次启动Activity都去读取并渲染View了。这确实是一个提高Activity启动速度的好方法。
    但是要注意,一旦View attach到Window上,就会持有一个Context(即Activity)的引用,而该View又是一个静态变量,所以导致Activity不被回收。

    优化:
    • 在使用静态View时,需要确保在资源回收时,将静态View detach掉。

    4 监听器(各种需要注册的Listener、Watcher等)

    当需要使用系统服务(比如执行某些后台任务、为硬件访问提供接口等等系统服务)时,需要把Activity自己注册到服务的监听器中,这会让服务持有Activity的引用,如果没有在Activity销毁时取消注册,那就会导致Activity泄漏。
    例如:EditText的addTextChangeListener,如果在回调方法里有耗时操作,可能会造成内存泄露。

    优化:
    • 在onDestory时,取消注册。
      比如:editText.removeTextChangedListener

    5 WebView

    在android 5.1及以上版本的代码中,WebView可能会存在内存泄露。
    (原因可以参考这篇文章:https://blog.csdn.net/u013085697/article/details/53259116

    优化:
    • 在销毁WebView前一定要onDetachedFromWindow,先将WebView从它的父View中移除再调用destroy方法。

    6 单例造成的内存泄漏

    单例的静态特性使得单例的生命周期和应用的生命周期一样长,这就说明了如果一个对象已经不需要使用了,而单例对象还持有该对象的引用,那么这个对象将不能被正常回收,这就导致了内存泄漏。

    7 线程死锁

    8 资源对象没有关闭

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

    9 属性动画

    在使用ValueAnimator或者ObjectAnimator时,如果没有及时做cancel取消动画,就可能造成内存泄露。
    因为在cancel方法里,最后调用了endAnimation(); ,在endAnimation里,有个AnimationHandler的单例,会持有属性动画对象的引用。

    优化:
    • 在onDestory时,调用动画的cancel方法

    10 其他的系统控件以及自定义View

    在 Android Lollipop 之前使用 AlertDialog 可能会导致内存泄漏,参考:https://blog.csdn.net/u012464435/article/details/50774580

    Dialog和DialogFragment在Android5.0以下的内存泄漏,参考:https://www.cnblogs.com/endure/p/7664320.htmlhttp://www.mamicode.com/info-detail-1753936.html

    11 TimerTask


    三、检测工具

    1 命令行查看内存占用情况

    adb shell dumpsys meminfo -a 包名
    

    2 AS自带的Monitors

    展示内存使用,及网络、CPU、GPU使用情况。

    3 LeakCanary

    随应用运行,实时监测。

    相关文章

      网友评论

          本文标题:Android内存泄漏

          本文链接:https://www.haomeiwen.com/subject/fdslfctx.html