使用Android studio分析内存泄露

截至Android Studio 1.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分析内存泄露


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没有回收它

使用Android studio分析内存泄露


EMA

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

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

使用Android studio分析内存泄露


GC root

使用Android studio分析内存泄露


Message in looper hold a reference to Activity

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

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

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

尝试使用static inner class来解决

现在把Runnable变成静态的class

使用Android studio分析内存泄露


StaticClass

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

使用Android studio分析内存泄露


StaticClass_memory_analyze

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

使用Android studio分析内存泄露


StaticClass_memory_analyze_explained

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

使用弱引用 + static Runnable

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

使用Android studio分析内存泄露


StaticClassWithWeakRef_code

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

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

使用Android studio分析内存泄露


StaticClassWithWeakRef_memory_analyze

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

所以,我们应该记住:

使用静态内部类

Handler/Runnable的依赖要使用弱引用。

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

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/3c9aeb4521542a5a0425f57ef348c171.html