使用Android studio分析内存泄露

转载 2015年11月02日 15:59:40
转自:http://www.jianshu.com/p/c49f778e7acf

使用Android studio分析内存泄露

This post is a permitted translation of badoo Tech Blog and I add some text and screenshots for android studio users.
Origin Author: Dmytro Voronkevych
follow badoo on Tweet
Translator: Miao1007

截至androidstudio1.3为止,其内部的MemoryDump功能都很难使用,还是使用MAT更佳。

Android使用java作为平台开发,帮助了我们解决了很多底层问题,比如内存管理,平台依赖等等。然而,我们也经常遇到OutOfMemoey问题,垃圾回收到底去哪了?

接下来是一个Handler Leak的例子,它一般会在编译器中被警告提示。

所需要的工具

  • Android Studio 1.1 or higher
  • Eclipse MemoryAnalyzer

示例代码

public class NonStaticNestedClassLeakActivity extends ActionBarActivity {

  TextView textView;

  public static final String TAG = NonStaticNestedClassLeakActivity.class.getSimpleName();

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_non_static_nested_class_leak);
    textView = (TextView)findViewById(R.id.textview);
    Handler handler = new Handler();

    handler.postDelayed(new Runnable() {
      @Override public void 
        textView.setText("Done");
      }//a mock for long time work
    }, 800000L);


  }
}

这是一个非常基础的Activity.注意这个匿名的Runnable被送到了Handler中,而且延迟非常的长。现在我们运行这个Activity,反复旋转屏幕,然后导出内存并分析。

导入 Memory 到Eclipse MemoryAnalyzer

使用Androidstudio导出 heap dump


Android Studio dump Memory Analyze
  • 点击左下角的Android
  • 选中你的程序的包名
  • 点击 initiates garbage collection on selected vm
  • 点击 dump java heap for selected client

打开MAT,进行分析

MAT是对java heap中变量分析的一个工具,它可以用于分析内存泄露。

  • 点击OQL图标
  • 在窗口输入select * from instanceof android.app.Activity并按Ctrl + F5或者!按钮
  • 奇迹出现了,现在你发现泄露了许多的activity
  • 这个真是相当的不容乐观,我们来分析一下为什么GC没有回收它


EMA

在OQL(Object Query Language)窗口下输入的查询命令可以获得所有在内存中的Activities,这段查询代码是不是非常简单高效呢?

点击一个activity对象,右键选中Path to GC roots


GC root


Message in looper hold a reference to Activity

在打开的新窗口中,你可以发现,你的Activity是被this$0</code>所引用的,它实际上是匿名类对当前类的引用。<code>this$0又被callback所引用,接着它又被Message中一串的next所引用,最后到主线程才结束。

任何情况下你在class中创建非静态内部类,内部类会(自动)拥有对当前类的一个强引用。

一旦你把Runnable或者Message发送到Handler中,它就会被放入LooperThread的消息队列,并且被保持引用,直到Message被处理。发送postDelayed这样的消息,你输入延迟多少秒,它就会泄露至少多少秒。而发送没有延迟的消息的话,当队列中的消息过多时,也会照成一个临时的泄露。

尝试使用static inner class来解决

现在把Runnable变成静态的class


StaticClass

现在,摇一摇手机,导出内存


StaticClass_memory_analyze

为什么又出现了泄露呢?我们看一看Activities的引用.


StaticClass_memory_analyze_explained

看到下面的mContext的引用了吗,它被mTextView引用,这样说明,使用静态内部类还远远不够,我们仍然需要修改。

使用弱引用 + static Runnable

现在我们把刚刚内存泄露的罪魁祸首 - TextView改成弱引用。


StaticClassWithWeakRef_code

再次注意我们对TextView保持的是弱引用,现在让它运行,摇晃手机

小心地操作WeakReferences,它们随时可以为空,在使用前要判断是否为空.


StaticClassWithWeakRef_memory_analyze

哇!现在只有一个Activity的实例了,这回终于解决了我们的问题。

所以,我们应该记住:

  • 使用静态内部类
  • Handler/Runnable的依赖要使用弱引用。

如果你把现在的代码与开始的代码相比,你会发现它们大不相同,开始的代码易懂简介,你甚至可以脑补出运行结果。

而现在的代码更加复杂,有很多的模板代码,当把postDelayed设置为一个短时间,比如50ms的情况下,写这么多代码就有点亏了。其实,还有一个更简单的方法。

onDestroy中手动控制声明周期

Handler可以使用removeCallbacksAndMessages(null),它将移除这个Handler所拥有的RunnableMessage

//Fixed by manually control lifecycle
  @Override protected void onDestroy() {
    super.onDestroy();
    myHandler.removeCallbacksAndMessages(null);
  }

现在运行,旋转手机,导出内存


removeCallbacks_memory_analyze

Good!只有一个实例。

这样写可以让你的代码更加简洁与可读。唯一要记住的就是就是要记得在生命周期onDestory的时候手动移除所有的消息。

使用WeakHander

(这个是第三方库,我就不翻译了,大家去Github上去学习吧)

结论

在Handler中使用postDelayed需要额外的注意,为了解决问题,我们有三种方法

  • 使用静态内部Handler/Runnable + 弱引用
  • 在onDestory的时候,手动清除Message
  • 使用Badoo开发的第三方的 WeakHandler

这三种你可以任意选用,第二种看起来更加合理,但是需要额外的工作。第三种方法是我最喜欢的,当然你也要注意WeakHandler不能与外部的强引用共同使用。

最后

本博客将长期保持原创性,翻译文章费时费力,如果你认为我的免费劳动有价值的话,不妨帮忙点赞或者关注我吧!




使用 Android Studio 检测内存泄漏与解决内存泄漏问题

本文在腾讯技术推文上 修改 发布。     http://wetest.qq.com/lab/view/63.html?from=ads_test2_qqtips&sessionUserType=B...
  • qq_27650777
  • qq_27650777
  • 2016年07月21日 16:21
  • 8343

使用Android Studio检测内存泄露

内存泄露,是Android开发者最头疼的事。可能一处小小的内存泄露,都可能是毁千里之堤的蚁穴。 怎么才能检测内存泄露呢? AndroidStudio 中Memory控件台(显示器)提供了一个内存监视...
  • zxc123e
  • zxc123e
  • 2016年10月25日 16:53
  • 5217

利用Android Studio、MAT对Android进行内存泄漏检测

项目进入维护阶段时才有时间测试分析app的内存问题,这时就要用到测试工具了,可以使用Android Studio、MAT互相结合进行测试, 但是对于复杂的,这两者很难分析出来,但这两测试工具也是必须掌...
  • yk377657321
  • yk377657321
  • 2016年09月07日 15:42
  • 1970

基于Android Studio的内存泄漏检测与解决全攻略

自从Google在2013年发布了Android Studio后,Android Studio凭借着自己良好的内存优化,酷炫的UI主题,强大的自动补全提示以及Gradle的编译支持正逐步取代Eclip...
  • jinhui157
  • jinhui157
  • 2017年06月28日 19:37
  • 615

Android Studio 分析内存泄漏

内存分析入门
  • cxq234843654
  • cxq234843654
  • 2016年04月26日 15:12
  • 4633

使用Android Studio调试内存问题

前言内存问题对于Android开发者是永远的痛。如果一个Android程序员说他没有遇到过OutOfMemory,那只能说他绝对不是做Android的。以往在ADT年代,都是使用eclipse的Mat...
  • yutao52shi
  • yutao52shi
  • 2015年11月26日 14:38
  • 8431

AndroidStudio Memory Monitor使用介绍

AndroidStudio 中Memory控件台(显示器)提供了一个内存监视器。 我们可以通过它方便地查看应用程序的性能和内存使用情况,从而也就可以找到需要释放对象,查找内存泄漏等。主要功能有:显示...
  • true100
  • true100
  • 2016年09月21日 10:06
  • 13490

基于Android Studio的内存泄漏检测与解决全攻略

自从Google在2013年发布了Android Studio后,Android Studio凭借着自己良好的内存优化,酷炫的UI主题,强大的自动补全提示以及Gradle的编译支持正逐步取代Eclip...
  • u010944680
  • u010944680
  • 2016年06月20日 16:16
  • 13076

Android Studio +MAT 分析内存泄漏实战

对于内存泄漏,在Android中如果不注意的话,还是很容易出现的,尤其是在Activity中,比较容易出现,下面我就说下自己是如何查找内存泄露的。首先什么是内存泄漏?内存泄漏就是一些已经不使用的对象还...
  • u012760183
  • u012760183
  • 2016年07月29日 20:45
  • 9702

使用新版Android Studio检测内存泄露和性能

内存泄露,是Android开发者最头疼的事。可能一处小小的内存泄露,都可能是毁于千里之堤的蚁穴。怎么才能检测内存泄露呢?网上教程非常多,不过很多都是使用Eclipse检测的, 其实1.3版本以后的An...
  • yangxi_001
  • yangxi_001
  • 2016年07月08日 14:57
  • 14953
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:使用Android studio分析内存泄露
举报原因:
原因补充:

(最多只允许输入30个字)