您现在的位置: 主页 > 嵌入式操作系统 > Android > Android内存泄漏案例和解析!
本文所属标签:
为本文创立个标签吧:

Android内存泄漏案例和解析!

来源:android 网络用户发布,如有版权联系网管删除 2018-09-09 



Android内训泄露会造成什么后果?内存泄露和什么有关?如何避免Android内存泄露?和达妹一起去看看这些让人受益匪浅的案例和解析!


Android 编程所使用的 Java 是一门使用垃圾收集器(GC,garbage collection)来自动管理内存的语言,它使得我们不再需要手动调用代码来进行内存回收。那么它是如何判断的呢?



简单说就是,如果一个对象,从它的根节点开始不可达的话,那么这个对象就是没有引用的了,是会被垃圾收集器回收的,其中,所谓的 “根节点” 往往是一个线程,比如主线程。因此,如果一个对象从它的根节点开始是可达的有引用的,但实际上它已经没有再使用了,是无用的,这样的对象就是内存泄漏的对象,它会在内存中占据我们应用程序原本就不是很多的内存,导致程序变慢,甚至内存溢出(OOM)程序崩溃。
内存泄漏的原因并不难理解,但仅管知道它的存在,往往我们还是会不知觉中写出致使内存泄漏的代码。在 Android 编程中,也是有许多情景容易导致内存泄漏,以下将一一列举一些我所知道的内存泄漏案例,从这些例子中应该能更加直观了解怎么导致了内存泄漏,从而在编程过程中去避免。
首先,比较简单的一种情况是,静态变量致使内存泄漏,但说到静态变量,我们至少得了解其生命周期才能彻底明白。静态变量的生命周期,起始于类的加载,终止于类的释放。对于 Android 而言,程序也是从一个 main 方法进入,开始了主线程的工作,如果一个类在主线程或旁枝中被使用到,它就会被加载,反过来说,假如一个类存在于我们的项目中,但它从未被我们使用过,算是个孤岛,这时它是没有被加载的。一旦被加载,只有等到我们的 Android 应用进程结束它才会被卸载。
于是,当我们在 Activity 中声明一个静态变量引用了 Activity 自身,就会造成内存泄漏:1       public class LeakActivity extends AppCompatActivity {2       private static Context sContext;3      @Override protected void onCreate(Bundle savedInstanceState) {4       super.onCreate(savedInstanceState);5       setContentView(R.layout.activity_leak);6       sContext = this;7        }8        }这样的代码会导致当这个 Activity 结束的时候,sContext 仍然持有它的引用,致使 Activity 无法回收。解决办法就是在这个 Activity 的onDestroy 时将sContext 的值置空,或者避免使用静态变量这样的写法。
同样的,如果一个 Activity 的静态 field 变量内部获得了当前 Activity 的引用,比如我们经常会把 this 传给 View 之类的对象,这个对象若是静态的,并且没有在 Activity 生命周期结束之前置空的话,也会导致同样的问题。
另外一个也是很常见的情景是,我们使用了后台线程,在线程中引用了当前 Activity 或它的子对象,子对象又间接引用了该 Activity,也会致使内存泄漏。比如我们经常会遇到的 Handler 问题,如果我们在 filed 声明一个 Handler 变量:1      private Handler mHandler = new Handler(){2     @Override public void handleMessage(Message msg) {3      super.handleMessage(msg);4      }5      }; 由于在 Java 中,非静态内部类(包括匿名内部类,比如这个 Handler 匿名内部类)会引用外部类对象(比如 Activity),而静态的内部类则不会引用外部类对象。所以这里 Handler 会引用 Activity 对象,当它使用了postDelayed 的时候,如果 Activity 已经 finish 了,而这个 handler 仍然引用着这个 Activity 就会致使内存泄漏,因为这个 handler 会在一段时间内继续被 mainLooper 持有,导致引用仍然存在,在这段时间内,如果内存吃紧至超出,就很危险了。
解决办法就是大家都知道的使用静态内部类加WeakReference1      private StaticHandler mHandler = new StaticHandler(this);2      public static class StaticHandler extends Handler {3      private final WeakReference<Activity> mActivity;4      public StaticHandler(Activity activity) {5      mActivity = new WeakReference<Activity>(activity);6      }7     @Override public void handleMessage(Message msg) {8      super.handleMessage(msg);9      }10    }另外,综合上面两种情况,如果一个变量,既是静态变量,而且是非静态的内部类对象,那么也会造成内存泄漏:
1     public class LeakActivity extendsAppCompatActivity {2     private static Hello sHello;3     @Override protected void onCreate(Bundle savedInstanceState) {4     super.onCreate(savedInstanceState);5     setContentView(R.layout.activity_leak);6     sHello = new Hello();7     }8     public class Hello {}9     }注意,这里我们定义的 Hello 虽然是空的,但它是一个非静态的内部类,所以它必然会持有外部类即 LeakActivity.this 引用,导致sHello 这个静态变量一直持有这个 Activity,于是结果就和第一个例子一样,Activity 无法被回收。

到这里大家应该可以看出,内存泄漏经常和静态变量有关。和静态变量有关的,还有一种常见情景,就是使用单例模式没有解绑致使内存泄漏,单例模式的对象经常是和我们的应用同样的生命周期,如果我们使用 EventBus 或 Otto 之类的单例,注册了一个 Activity 而没有在页面结束的时候进行接触注册,那么单例会一直持有我们的 Activity,这个 Activity 虽然没有使用了,但会一直占用着内存。


微信关注公众号回复字母查看文章


回复A  学习Android薪资及开发技巧

回复B  安卓程序猿圈劲爆资讯回复C  程序员升职记回复D 2016 移动互联行情

我们是一群热爱IT的年轻人,如果你也爱IT、爱移动端开发,欢迎加入我们,让我们共同为梦想发声。Android开发QQ:3264778080


选达内=4个月=高薪就业


长按二维码即可识别关注↓↓↓




              查看评论 回复



嵌入式交流网主页 > 嵌入式操作系统 > Android > Android内存泄漏案例和解析!
 静态 我们 内存

"Android内存泄漏案例和解析!"的相关文章

网站地图

围观()