Android性能优化-内存泄漏2

时间:2022-12-06 06:03:57
Android使用handler时的内存问题 上篇文章http://blog.csdn.net/qiaoqiao_miss/article/details/52096839 已经介绍来关于Android内存泄漏的几个问题,如需了解,请前往,这篇文章主要讲解Android 使用线程时出现的内存泄漏问题。 发现这个也是一个偶然的机会,业务逻辑是这样的 : Activity A ,B ;A中有一倒计时器,倒计时是自定义view C,计时是通过另外开了一个工作线程D,当倒计时为0分时D线程中会使用handler 发消息给 Cview 的监听会 刷新A的数据(刷新前后页面显示不同); 问题出在哪里了呢? 当A开始倒计时了,跳转到B 页面(此时A已经调用finish()),当A倒计时结束,---------》A会回到栈顶,并显示新数据
为什么? 首先我们需要知道一下知识点: 不要认为Java会为你清理runningthread。在上面的例子中,我们会很容易的就想象当用户离开这个Activity的时候,Activity实例会被垃圾回收器回收,所有在这个Activity中开启的running thread也会被清理掉。事实上不是这样的。Java线程将会一直存在,直到他们被显示的关闭或者处理结束,或者被杀掉整个进程。
那么面对这样的问题 我们该如何解决呢? 先看一个简单的栗子:Android性能优化-内存泄漏2 框出来的部分已经犯法了,那我们如何解决呢?1.给一个标志位,如果activity 被销毁后,不需要Thread中继续操作 那个我们可以给出一个标志位;
Android性能优化-内存泄漏2

2.在onDestroy中直接调用thread.join();对于HandlerThread应调用 thread.getLooper().quit();Android性能优化-内存泄漏2

解决方法先讲到这里,当大家看到第一个图的时候,明眼人是不是已经看出来另外一个内存泄漏的问题。是什么呢?大写的Handler.为什么?
在这里我们再来复习一下java基础:非静态内部类和静态内部类的区别之一:是否拥有指向外部类对象的引用。非静态内部类:可以访问创建它得外部类对象的全部内容,甚至包括私有,要想实现这个,内部类的对象就必须有指向外部类对象的引用。Java编译器在创建内部类对象时,隐式的把其外部类对象的引用也传了进去,并一直保存着。这样就使得内部类对象始终可以访问其外部对象,同时这也是在外部类作用范围之外创建内部类对象时必须先创建其外部类对象的原因。

那么回到图一就会发现handler 是一个非静态的内部类,如果我们要在这个activity的作用范围外使用,那么它将始终持有activity的引用,造成内存不能释放,导致内存泄漏。需要注意的是泄露同样发生在匿名的runnable类中,非静态的匿名类也保持了一个对外部的引用,也会导致context 泄露。
要解决以上问题方法一:Android性能优化-内存泄漏2

因为 静态内部类 不持有外部类的引用。如果你需要在Handler中访问外部activity的方法,可以在Handler中保持一个对Activity的WeakReference,这样就不会发生内存泄漏(上一篇文章有介绍)

静态内部类和非静态内部类的区别很微小,那么如何选择?当内部类可以独立于Activity的生命周期而存在的时候,应该避免使用非静态的内部类,应该用静态内部类并且使用WeakReference保持对Activity的引用。


下一篇文章想给大家讲一下Android内存泄漏检测工具,还未研究,请期待吧。。。