android 内存优化一
2015-06-09 14:09
381 查看
常见内存泄露原因
Context对象泄漏
1、如果一个类持有Context对象的强引用,就需要检查其生存周期是否比Context对象更长。否则就可能发生Context泄漏。
2、View持有其创建所在Context对象的引用,如果将View对象传递给其它生存周期比View所在Context更长的强引用,就可能会引起内存泄漏。
例如View#setTag(int, Object)的内存泄漏https://code.google.com/p/android/issues/detail?id=18273
3、把Context对象赋给static变量。
避免Context对象泄漏Checklist
1、检查所有持有对Context对象强引用的对象的生命周期是否超出其所持有的Context对象的生命周期。
2、检查有没有把View传出到View所在Context之外的地方,如果有的话就需要检查生命周期。
3、工具类中最好不要有Context成员变量,尽量在调用函数时直接通过调用参数传入。如果必须有Context成员变量时,可以考虑使用WeakReference来引用Context对象。
4、View持有其创建所在Context对象的引用,如果将View对象传递给其它生存周期比View所在Context更长的强引用,就可能会引起内存泄漏。
5、 检查把Context或者View对象赋给static变量的地方,看是否有Context泄漏。
6、检查所有把View放入容器类的地方(特别是static容器类),看是否有内存泄漏。7、使用WeakHashMap也需要注意有没有value-key的引用。
7、尽量使用ApplicationContext。
Handler对象泄漏
1、发送到Handler的Message实际上是加入到了主线程的消息队列等待处理,每一个Message持有其目标Handler的强引用。
如我们通常使用的匿名内部类Handler
上面是一段简单的Handler的使用。当使用内部类(包括匿名类)来创建Handler的时候,Handler对象会隐式地持有一个外部类对象 (通常是一个Activity)的引用,因为View会依附着一个Activity。而Handler通常会伴随着一个耗时的后台线程(例如从网络拉取图 片)一起出现,这个后台线程在任务执行完毕(例如图片下载完 毕)之后,通过消息机制通知Handler,然后Handler把图片更新到界面。然而,如果用户在网络请求过程中关闭了Activity,正常情况 下,Activity不再被使用,它就有可能在GC检查时被回收掉,但由于这时线程尚未执行完,而该线程持有Handler的引用(不然它怎么发消息给 Handler?),这个Handler又持有Activity的引用,就导致该Activity无法被回收(即内存泄露),直到网络请求结束(例如图片 下载完毕)。另外,如果你执行了Handler的postDelayed()方法,该方法会将你的Handler装入一个Message,并把这条 Message推到MessageQueue中,那么在你设定的delay到达之前,会有一条MessageQueue -> Message -> Handler -> Activity的链,导致你的Activity被持有引用而无法被回收。
当然,应为是Handler对外部持有引用的原因,我们就可以将Activity设置为一个弱引用,在不必要的时候,不再执行内部方法。
避免内部Getters/Setters
在Android中,虚方法调用的代价比直接字段访问高昂许多。通常根据面向对象语言的实践,在公共接口中使用Getters和Setters是有道理的,但在一个字段经常被访问的类中宜采用直接访问。
避免使用浮点数
通常的经验是,在Android设备中,浮点数会比整型慢两倍。
Adapter适配器
在Android中Adapter使用十分广泛,特别是在list中。所以adapter是数据的 “集散地” ,所以对其进行内存优化是很有必要的。
下面算是一个标准的使用模版:
主要使用convertView和ViewHolder来进行缓存处理
View Code
使用软引用以后,在OutOfMemory异常发生之前,这些缓存的图片资源的内存空间可以被释放掉的,从而避免内存达到上限,避免Crash发生。
需要注意的是,在垃圾回收器对这个Java对象回收前,SoftReference类所提供的get方法会返回Java对象的强引用,一旦垃圾线程回收该 Java对象之后,get方法将返回null。所以在获取软引用对象的代码中,一定要判断是否为null,以免出现 NullPointerException异常导致应用崩溃。
到底什么时候使用软引用,什么时候使用弱引用呢?
个人认为,如果只是想避免OutOfMemory异常的发生,则可以使用软引用。如果对于应用的性能更在意,想尽快回收一些占用内存比较大的对象,则可以使用弱引用。
还有就是可以根据对象是否经常使用来判断。如果该对象可能会经常使用的,就尽量用软引用。如果该对象不被使用的可能性更大些,就可以用弱引用。
另外,和弱引用功能类似的是WeakHashMap。WeakHashMap对于一个给定的键,其映射的存在并不阻止垃圾回收器对该键的回收,回收以后,其条目从映射中有效地移除。WeakHashMap使用ReferenceQueue实现的这种机制。
Context对象泄漏
1、如果一个类持有Context对象的强引用,就需要检查其生存周期是否比Context对象更长。否则就可能发生Context泄漏。
2、View持有其创建所在Context对象的引用,如果将View对象传递给其它生存周期比View所在Context更长的强引用,就可能会引起内存泄漏。
例如View#setTag(int, Object)的内存泄漏https://code.google.com/p/android/issues/detail?id=18273
3、把Context对象赋给static变量。
避免Context对象泄漏Checklist
1、检查所有持有对Context对象强引用的对象的生命周期是否超出其所持有的Context对象的生命周期。
2、检查有没有把View传出到View所在Context之外的地方,如果有的话就需要检查生命周期。
3、工具类中最好不要有Context成员变量,尽量在调用函数时直接通过调用参数传入。如果必须有Context成员变量时,可以考虑使用WeakReference来引用Context对象。
4、View持有其创建所在Context对象的引用,如果将View对象传递给其它生存周期比View所在Context更长的强引用,就可能会引起内存泄漏。
5、 检查把Context或者View对象赋给static变量的地方,看是否有Context泄漏。
6、检查所有把View放入容器类的地方(特别是static容器类),看是否有内存泄漏。7、使用WeakHashMap也需要注意有没有value-key的引用。
7、尽量使用ApplicationContext。
Handler对象泄漏
1、发送到Handler的Message实际上是加入到了主线程的消息队列等待处理,每一个Message持有其目标Handler的强引用。
如我们通常使用的匿名内部类Handler
HandlermHandler = new Handler() { @Override public voidhandleMessage(Message msg) { mImageView.setImageBitmap(mBitmap); } }
上面是一段简单的Handler的使用。当使用内部类(包括匿名类)来创建Handler的时候,Handler对象会隐式地持有一个外部类对象 (通常是一个Activity)的引用,因为View会依附着一个Activity。而Handler通常会伴随着一个耗时的后台线程(例如从网络拉取图 片)一起出现,这个后台线程在任务执行完毕(例如图片下载完 毕)之后,通过消息机制通知Handler,然后Handler把图片更新到界面。然而,如果用户在网络请求过程中关闭了Activity,正常情况 下,Activity不再被使用,它就有可能在GC检查时被回收掉,但由于这时线程尚未执行完,而该线程持有Handler的引用(不然它怎么发消息给 Handler?),这个Handler又持有Activity的引用,就导致该Activity无法被回收(即内存泄露),直到网络请求结束(例如图片 下载完毕)。另外,如果你执行了Handler的postDelayed()方法,该方法会将你的Handler装入一个Message,并把这条 Message推到MessageQueue中,那么在你设定的delay到达之前,会有一条MessageQueue -> Message -> Handler -> Activity的链,导致你的Activity被持有引用而无法被回收。
当然,应为是Handler对外部持有引用的原因,我们就可以将Activity设置为一个弱引用,在不必要的时候,不再执行内部方法。
import android.app.Activity; importandroid.content.Context; importandroid.os.Handler; importandroid.os.Message; importjava.lang.ref.WeakReference; publicclass WeakRefHandler extends Handler { WeakReference<context> mWeakContext; public WeakRefHandler(Context context) { mWeakContext = newWeakReference<context>(context); } @Override public void handleMessage(Message msg) { if((mWeakContext.get() instanceofActivity )&& ((Activity)mWeakContext.get()).isFinishing()) return ; if(mWeakContext==null){ return ; } super.handleMessage(msg); } }
避免内部Getters/Setters
在Android中,虚方法调用的代价比直接字段访问高昂许多。通常根据面向对象语言的实践,在公共接口中使用Getters和Setters是有道理的,但在一个字段经常被访问的类中宜采用直接访问。
避免使用浮点数
通常的经验是,在Android设备中,浮点数会比整型慢两倍。
Adapter适配器
在Android中Adapter使用十分广泛,特别是在list中。所以adapter是数据的 “集散地” ,所以对其进行内存优化是很有必要的。
下面算是一个标准的使用模版:
主要使用convertView和ViewHolder来进行缓存处理
//首先定义一个HashMap,保存软引用对象。 private Map<String, SoftReference<Bitmap>> imageCache = new HashMap<String, SoftReference<Bitmap>>(); //再来定义一个方法,保存Bitmap的软引用到HashMap。 public void addBitmapToCache(String path) { // 强引用的Bitmap对象 Bitmap bitmap = BitmapFactory.decodeFile(path); // 软引用的Bitmap对象 SoftReference<Bitmap> softBitmap = new SoftReference<Bitmap>(bitmap); // 添加该对象到Map中使其缓存 imageCache.put(path, softBitmap); } //获取的时候,可以通过SoftReference的get()方法得到Bitmap对象。 public Bitmap getBitmapByPath(String path) { // 从缓存中取软引用的Bitmap对象 SoftReference<Bitmap> softBitmap = imageCache.get(path); // 判断是否存在软引用 if (softBitmap == null) { return null; } // 取出Bitmap对象,如果由于内存不足Bitmap被回收,将取得空 Bitmap bitmap = softBitmap.get(); return bitmap; }
View Code
使用软引用以后,在OutOfMemory异常发生之前,这些缓存的图片资源的内存空间可以被释放掉的,从而避免内存达到上限,避免Crash发生。
需要注意的是,在垃圾回收器对这个Java对象回收前,SoftReference类所提供的get方法会返回Java对象的强引用,一旦垃圾线程回收该 Java对象之后,get方法将返回null。所以在获取软引用对象的代码中,一定要判断是否为null,以免出现 NullPointerException异常导致应用崩溃。
到底什么时候使用软引用,什么时候使用弱引用呢?
个人认为,如果只是想避免OutOfMemory异常的发生,则可以使用软引用。如果对于应用的性能更在意,想尽快回收一些占用内存比较大的对象,则可以使用弱引用。
还有就是可以根据对象是否经常使用来判断。如果该对象可能会经常使用的,就尽量用软引用。如果该对象不被使用的可能性更大些,就可以用弱引用。
另外,和弱引用功能类似的是WeakHashMap。WeakHashMap对于一个给定的键,其映射的存在并不阻止垃圾回收器对该键的回收,回收以后,其条目从映射中有效地移除。WeakHashMap使用ReferenceQueue实现的这种机制。
相关文章推荐
- Android -----listView的属性大全
- Android从入门到精通第四章 消息提示框与对话框
- Android 映像文件 system.img, boot.img, ramdisk.img, userdata.img.
- Android Framework 记录之一
- Android dumpstate 工具解析
- 【Android】ListView动态视图显示不全
- android 工程引入官方doc注释的方法:
- Android 控件 之 Menu 菜单
- Android开发:使用序列化接口Parcelable、Serializable实现Activity间传递复杂数据类型参数
- golang服务器+android 生成相同md5码
- 关于ListView的getView()方法调用多次问题
- Android 修改debug证书出现:Keystore was tampered with, or password was incorrect 问题解决
- Android HAL(硬件抽象层)介绍以及调用
- Android自定义View基础(1)
- Android4.0反编译笔记
- Android Studio 相关-快捷键、常见问题
- Android 省市县 三级联动(android-wheel的使用)
- Android 5.0 如何正确启用isLoggable(二)__原理分析
- Android SDK Manager需要下载类目
- Android OOM 问题的总结