安卓内存泄漏8种可能

Posted 小#安

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了安卓内存泄漏8种可能相关的知识,希望对你有一定的参考价值。

     java垃圾回收器,开发者无需特意管理内存分配,降低了应用由于局部故障导致崩溃,同时防止未释放的内存把堆栈挤爆的可能,所以写出的代码更为安全。

         但是,在java中仍存在很多容易导致内存泄漏的逻辑可能。如果不小心,则很容易浪费掉未释放的内存,最终导致内存用光的错误抛出OOM

         内存泄漏

  1. 一般内存泄漏(traditional memory leak):由忘记释放分配的内存导致的(Cursor忘记关闭等)
  2. 逻辑内存泄漏(logical memory leak):当应用不再需要这个对象,但仍未释放该对象的所有引用

 

如果持有对象的强引用,垃圾回收器是无法在内存中回收这个对象

       android 中,最容易引发的内存泄漏为 Context,如Activity的Context,就包含了大量的内存引用,如View Hierarchies和其他资源。一旦泄漏Context,就意味着泄漏它指向的所有对象。android机器内存有限,太多的内存泄漏容易导致OOM

       Activity.onDestroy()被视为Activity生命的结束,程序上看来,它应该被销毁,或者Android系统需要回收这些内存(当内存不够时,android会回收看不见的activity)

       如果Activity.onDestroy()执行完,堆栈中仍存在持有该activity的引用,垃圾回收器就无法把他标记成已回收的内存(结果就是Activity存活在它的生命周期之外)

       导致潜在的内存泄漏的陷阱不外乎两种:

  1. 全局进程(process-global)的static变量。这个无视应用状态,持有activity的强引用的东西
  2. 活在Activity生命周期之外的线程。没有清空对Activity的强引用。

----------------------------------------------------------------------------------------------------------------

Static Activity

       在类中定义了静态Activity变量,把当前运行的activity实例赋值于这个静态变量。

        如果这个静态变量在activity生命结束后没有清空,就会导致内存泄漏。因为static贯穿了这个应用的生命周期,所以被泄露的Activity就会一直存在于应用的进程中,不会被垃圾回收器回收。 

 

       避免这种代码        static Activity activity;

----------------------------------------------------------------------------------------------------------------

Static Views      单例中保存activity

        在单例中,如果Activity经常被用到,那么内存中保存一个实例是很实用的。但由于单例的生命周期是应用程序的生命周期,这样做会延长Activity的生命周期(强制延长Activity的生命周期是相当危险且不必要的,无论如何都不能在单例中保存类似的Activity对象)

         特殊情况:如果一个View初始化耗费大量资源,而且在一个activity生命周期内保持不变,那可以把它变成static,加载到视图树上(View Hierachy),像这样,当activity被销毁时,应当释放资源。(在销毁视图时应该把这个static view的view置为null)

 

        在调用Singleton的getInstance()方法时传入了Activity,那么当instance 没有释放时,这个Activity会一直存在。因此造成内存泄漏。

         可以在传入context时传入context.getApplicationContext()即可

          static view也不建议,或者应该在销毁时置null

        Inner Classes:提高可读性,但是导致内存泄漏的原因,就是内部持有外部类实例的强引用,如内部类中持有Activity对象

        解决办法,1.将内部类变为静态内部类,把匿名内部类变为静态匿名内部类

                          2.如果有强引用Activity中的属性,则将该属性的引用方式改为弱引用

                          3.在业务运行的情况下,当Activity执行onDestroy时,结束这些耗时任务

----------------------------------------------------------------------------------------------------------------

Inner Classes

        假设Activity中有个内部类,这样做可以提高可读性和封装性。假如我们创建一个内部类,而且持有一个静态变量的引用,那么很有可能内存泄漏(销毁的时候置空即可)

        内部类的优势之一就是可以访问外部类,不好的是,导致内存泄漏的原因,就是因为内部类持有外部类实例的引用。

----------------------------------------------------------------------------------------------------------------

Anonymous Classes

        匿名类也维护了外部类的引用。所以内存泄漏很容易发生,当你在Activity中定义了匿名的AsyncTask。当阴补任务在后台执行耗时任务期间,Activity不幸被销毁(用户退出,系统回收),这个被AsyncTask持有的Activity实例就不会被垃圾回收器回收,直到异步任务结束。

----------------------------------------------------------------------------------------------------------------

Handler

         同样,定义匿名的Runnable,用匿名Handler执行。Runnable内部类会持有外部类的隐式引用,被传递到Handler的消息队列MessageQueue中,在Message消息没有被处理之前,Activity实例不会被销毁,于是导致了内存泄漏。

----------------------------------------------------------------------------------------------------------------

Threads

        只要是匿名类的实例,不管是不是在工作线程,都会持有Activity的引用,导致内存泄漏

----------------------------------------------------------------------------------------------------------------

TimerTask

        只要是匿名类的实例,不管是不是在工作线程,都会持有Activity的引用,导致内存泄漏

----------------------------------------------------------------------------------------------------------------

Sensor Manager

         通过Context.getSystemService(int name) 可获取系统服务。这些服务工作在各自的进程中,帮助应用处理后台任务,处理硬件交互。如果需要使用这些服务,可注册监听器,这会导致服务持有了Context的引用,如果在Activity销毁的时候没有注销这些监听,会导致内存泄漏

 

 

http://tryenough.com/android-momeryleak内存泄漏及解决方式

 

以上是关于安卓内存泄漏8种可能的主要内容,如果未能解决你的问题,请参考以下文章

常见的八种导致 APP 内存泄漏的问题(上)

安卓内存分析——常见内存泄漏场景二

安卓常见引起内存泄漏的五种情况

可能会导致.NET内存泄露的8种行为

Java内存泄漏的几种可能

排查内存泄漏最简单和直观的方法