截至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 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所引用的,它实际上是匿名类对当前类的引用。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的依赖要使用弱引用。
如果你把现在的代码与开始的代码相比,你会发现它们大不相同,开始的代码易懂简介,你甚至可以脑补出运行结果。

