Welcome 微信登录
编程资源 图片资源库 蚂蚁家优选 PDF转换器

首页 / 操作系统 / Linux / 使用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();@Overrideprotected 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的依赖要使用弱引用。
如果你把现在的代码与开始的代码相比,你会发现它们大不相同,开始的代码易懂简介,你甚至可以脑补出运行结果。而现在的代码更加复杂,有很多的模板代码,当把postDelayed设置为一个短时间,比如50ms的情况下,写这么多代码就有点亏了。其实,还有一个更简单的方法。

onDestroy中手动控制声明周期

Handler可以使用removeCallbacksAndMessages(null),它将移除这个Handler所拥有的RunnableMessage//Fixed by manually control lifecycle@Override protected void onDestroy() {super.onDestroy();myHandler.removeCallbacksAndMessages(null);}现在运行,旋转手机,导出内存 
removeCallbacks_memory_analyzeGood!只有一个实例。这样写可以让你的代码更加简洁与可读。唯一要记住的就是就是要记得在生命周期onDestory的时候手动移除所有的消息。

使用WeakHander

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

结论

在Handler中使用postDelayed需要额外的注意,为了解决问题,我们有三种方法
  • 使用静态内部Handler/Runnable + 弱引用
  • 在onDestory的时候,手动清除Message
  • 使用Badoo开发的第三方的 WeakHandler
这三种你可以任意选用,第二种看起来更加合理,但是需要额外的工作。第三种方法是我最喜欢的,当然你也要注意WeakHandler不能与外部的强引用共同使用。更多Android Studio相关内容可以看看以下的有用链接: 在Ubuntu 15.04下安装Android Studio  http://www.linuxidc.com/Linux/2015-06/119318.htm Android Studio 2.0中的模拟器已提速50倍  http://www.linuxidc.com/Linux/2015-11/125481.htmUbuntu 12.04(64位)安装Android Studio 全过程 http://www.linuxidc.com/Linux/2013-05/84812.htm Android Studio v0.1尝鲜 http://www.linuxidc.com/Linux/2013-05/84681.htm Android Studio使用教程 http://www.linuxidc.com/Linux/2013-05/84579.htm Android Studio开发指南 http://www.linuxidc.com/Linux/2013-05/84543.htmAndroid Studio设置主题 和 不支持中文的问题解决方法 http://www.linuxidc.com/Linux/2013-05/84488.htm Android Studio 下载安装以及不能打开的解决办法 http://www.linuxidc.com/Linux/2013-05/84409.htm Android Studio安装使用图文教程 http://www.linuxidc.com/Linux/2014-09/106914.htm Ubuntu上安装Android Studio 1.3(谷歌 Android IDE 开发)  http://www.linuxidc.com/Linux/2015-08/121004.htm Android Studio 的详细介绍:请点这里
Android Studio 的下载地址:请点这里 本文永久更新链接地址:http://www.linuxidc.com/Linux/2016-01/127202.htm