Android内存泄漏研究_最新动态_新闻资讯_程序员俱乐部

中国优秀的程序员网站程序员频道CXYCLUB技术地图
热搜:
更多>>
 
您所在的位置: 程序员俱乐部 > 新闻资讯 > 最新动态 > Android内存泄漏研究

Android内存泄漏研究

 2015/1/6 14:29:49    程序员俱乐部  我要评论(0)
  • 摘要:文/@寒江不钓(贾吉鑫)概念根搜索算法Android虚拟机的垃圾回收采用的是根搜索算法。GC会从根节点(GCRoots)开始对heap进行遍历。到最后,部分没有直接或者间接引用到GCRoots的就是需要回收的垃圾,会被GC回收掉。根搜索算法相比引用计数法很好的解决了循环引用的问题。举个例子,Activity有View的引用,View也有Activity的引用,之前我还尝试去源代码里找Activity何时和View断开连接是大错特错了。当Activityfinish掉之后
  • 标签:android 研究 内存
class="topic_img" alt=""/>

  文/@寒江不钓(贾吉鑫)

  概念

  根搜索算法

  Android 虚拟机的垃圾回收采用的是根搜索算法。GC 会从根节点(GC Roots)开始对 heap 进行遍历。到最后,部分没有直接或者间接引用到 GC Roots 的就是需要回收的垃圾,会被 GC 回收掉。

  根搜索算法相比引用计数法很好的解决了循环引用的问题。举个例子,Activity 有 View 的引用,View 也有 Activity 的引用,之前我还尝试去源代码里找 Activity 何时和 View 断开连接是大错特错了。当 Activity finish 掉之后,Activity 和 View 的循环引用已成孤岛,不再引用到 GC Roots,无需断开也会被回收掉。

  内存泄漏

  Android 内存泄漏指的是进程中某些对象(垃圾对象)已经没有使用价值了,但是它们却可以直接或间接地引用到 gc roots 导致无法被 GC 回收。无用的对象占据着内存空间,使得实际可使用内存变小,形象地说法就是内存泄漏了。

  场景

  • 类的静态变量持有大数据对象
    静态变量长期维持到大数据对象的引用,阻止垃圾回收。
  • 非静态内部类的静态实例
    非静态内部类会维持一个到外部类实例的引用,如果非静态内部类的实例是静态的,就会间接长期维持着外部类的引用,阻止被回收掉。
  • 资源对象未关闭
    资源性对象如 Cursor、File、Socket,应该在使用后及时关闭。未在 finally 中关闭,会导致异常情况下资源对象未被释放的隐患。
  • 注册对象未反注册
    未反注册会导致观察者列表里维持着对象的引用,阻止垃圾回收。
  • Handler临时性内存泄露
    Handler 通过发送 Message 与主线程交互,Message 发出之后是存储在 MessageQueue 中的,有些 Message 也不是马上就被处理的。在 Message 中存在一个 target,是 Handler 的一个引用,如果 Message 在 Queue 中存在的时间越长,就会导致 Handler 无法被回收。如果 Handler 是非静态的,则会导致 Activity 或者 Service 不会被回收。
    由于 AsyncTask 内部也是 Handler 机制,同样存在内存泄漏的风险。
    此种内存泄露,一般是临时性的。

  预防

  • 不要维持到 Activity 的长久引用,对 activity 的引用应该和 activity 本身有相同的生命周期。
  • 尽量使用context-application代替context-activity
  • Activity 中尽量不要使用非静态内部类,可以使用静态内部类和WeakReference代替。

  检测

  静态检测

  静态检测主要是检测资源未关闭的情况,Eclipse 和 Android Studio 都可以检测出 IO 或者 Socket 未关闭的情况,然后在 finally 中关闭即可。

  动态监测

  动态检测主要是依靠 MAT 这个工具。2011 年 Google IO 有一个主题演讲,非常详细地讲解了内存泄露的检测,包含 MAT 工具的使用,值得一看。我在某项目中使用 MAT 检测,发现一处内存泄漏,分享一下过程。从首页到商户列表到商户详情再退回首页执行Dump HPROF File,查看 MAT 中的Histogram,过滤 Activity 后,结果如下:

HistogramHistogram

仍然存在ShopInfoActivity的实例,选中右键点击Merge Shortest Paths to GC Roots,结果如下:

此处输入图片的描述

此处输入图片的描述

  可以看到ShopDatabase中维持着ShopInfoActivity的引用,查看源代码如下:

public class ShopDatabase {
           …
           private static ShopDatabase instance;
           public static ShopDatabase getInstance (Context context) {
               if (instance == null && context != null) {
                   instance = new ShopDatabase (context);
               }
               return instance;
           }
           protected Context context;
           …
       } 

  很明显,静态变量instance长期持有context的引用,造成内存泄露。
所以动态检测内存泄露的一个简单思路就是随意操作 APP,最后返回首页,然后用 MAT 检测,查看是否存在 Activity 多于一个或者 Activity 不正常存在的问题。

  参考资料

  • Avoiding memory leaks
  • Memory Analysis for Android Applications
  • memory_management_for_android_apps
  • Google IO:Android 内存管理主题演讲记录
  • Android 内存泄漏分析及调试
发表评论
用户名: 匿名