Android开发—内存优化(初步)

来源:互联网 发布:spring mvc返回json 编辑:程序博客网 时间:2024/06/05 22:36

这篇文章是关于这两天Android内存优化学习的记录,包括Android内存泄露的原因,Eclipse MAT工具的使用等。

参考文章:
  • http://blog.tisa7.com/tech/android_memory_management_and_solve_oom_problem.html
    这篇文章写得很详细,很受益,我就拿里面几个我在项目中碰到的实例,来分析一下。

准备工具

Eclipse MAT 下载地址: http://download.eclipse.org/mat/1.4/update-site/
直接在install new software中下载即可

工具使用

打开DDMS视图,如果已经安装了MAT,会有以下的图标
这里写图片描述
中间红色向下箭头的就是MAT分析的按钮,点击会生成分析文件,如下图所示:
这里写图片描述

这个就是我的应用程序跑出来的结果。他会自动总结一些内存泄露的对象,例如:
这里写图片描述
显示ImageView对象占用了很多内存,而此时这些对象原本应该是被释放的,但是没有!点击Details也可以具体看哪里引用这个对象的对象。
这里写图片描述
这个Details中可以看出:是我的mListView对象显示的ImageView中的Bitmap没有被释放,导致了内存泄露。
这个问题的出现,可以用上述网站的一个方面来描述,以下是引用内容:

内部类怎样使用才会产生内存泄露,以及由此衍生的AsyncTask、Handler问题如何解决?
如果非静态内部类的方法中,有生命周期大于其所在类的,那就有问题了。比如:AsyncTask、Handler,这两个类都是方便开发者执行异步任务的,但是,这两个都跳出了Activity/Fragment的生命周期。(或许,是时候学习Loader了)
为什么?因为非静态内部类会自动持有一个所属类的实例,如果所属类的实例已经结束生命周期,但内部类的方法仍在执行,就会hold其主体。也就使主体不能被释放,亦即内存泄露。
静态类呢?静态类编译后和非内部类是一样的,有自己独立的类名。不会悄悄引用所属类的实例,所以就不容易泄露。

所以,使用静态内部类,并且配上弱引用来使用AsyncTask。

直方图分析:

这里写图片描述
这是分析结果页面中的图标,点击第二个,会有如下的结果:
这里写图片描述
我这里是做了一个过滤,可以看到其中MainActivity对象有两个,首先,是我的MainActivity对象使用Standard方式加载,从而会出现这样的情况,那么来也可以看一下另外一个MainActivity为什么没有被回收。
点击右键,选择“Merge shortest paths to GC Roots”, 然后exclude …, 可以找出该实例关联的一些对象。
这里写图片描述
可以看到,我们这里MainActivity之所以没有被回收,是因为mMap还在被使用。
而我之前很常见的一个问题是Activity所关联的Context还在被使用,所以,又引出了一个内存泄露的问题,以下同样为引用文字:

需要context的时候用activity还是application?
看使用的周期是否在activity周期内,如果超出,必须用application;常见的情景包括:AsyncTask,Thread,第三方库初始化等等。
还有些情景,只能用activity:比如,对话框,各种View,需要startActivity的等。
总之,尽可能使用Application。参考stackoverflow

目前就分析这样两个问题,项目中的代码也需要进一步改进,后面还会进一步对Android内存泄露做一些学习。

ps:csdn居然也支持markdown了

0 0
原创粉丝点击