转自: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

使用Android studio分析内存泄露_第1张图片
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

使用Android studio分析内存泄露_第2张图片
StaticClass

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

使用Android studio分析内存泄露_第3张图片
StaticClass_memory_analyze

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

使用Android studio分析内存泄露_第4张图片
StaticClass_memory_analyze_explained

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

使用弱引用 + static Runnable

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

使用Android studio分析内存泄露_第5张图片
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不能与外部的强引用共同使用。

最后

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




更多相关文章

  1. Android近百个项目的源代码
  2. Android代码速查,写给新手的朋友们
  3. Java代码设置Android全屏
  4. android 内存管理
  5. [置顶] Android 代码混淆 选项说明
  6. android秒表计时代码
  7. android代码片段一
  8. Android Camera子系统代码流程1
  9. android文件缓存,并SD卡创建目录未能解决和bitmap内存溢出解决

随机推荐

  1. 2011年Android产品趋势
  2. Android EditText 一些属性设置
  3. EditText的使用
  4. Android 输入法键盘和activity页面遮挡问
  5. Android 绘制中国地图及热点省份分布
  6. android 7和android8在user版本下能应用
  7. Android(安卓)NDK standlone编译脚本
  8. Android skia 和open skia的比较
  9. 通过 Android SDK Manager 安装面向 Andr
  10. 常用的布局和View常用属性