android 开发内存溢出处理方法

首先我们来看看android内存溢出的原因,有可能是:

  1. 由于我们程序的失误,长期保持某些资源(如Context)的引用,造成内存泄露,资源造成得不到释放。
  2. 保存了多个耗用内存过大的对象(如Bitmap),造成内存超出限制。

一旦出现了内存溢出,一般情况下从以下几个方面入手:

  1. 从内存引用上做处理,常用的有软引用,强化引用,弱引用。
  2. 在内存中加载图片时直接在内存中作处理,比如边界压缩。。。
  3. 动态回收内存
  4. 优化虚拟机堆内存分配
  5. 自定义堆内存大小

解决方案:

a. 强引用、软引用等的介绍

heap中对象有强可及对象、软可及对象、弱可及对象、虚可及对象和不可到达对象。应用的强弱顺序是强、软、弱、和虚。对于对象是属于哪种可及的对象,由他的最强的引用决定
强引用:只要存在对heap中对象的引用,gc就不会收集该对象.
软引用:软引用是主要用于内存敏感的高速缓存。在jvm报告内存不足之前会清除所有的软引用,这样以来gc就有可能收集软可及的对象,可能解决内存吃紧问题,避免内存溢出。什么时候会被收集取决于gc的算法和gc运行时可用内存的大小。当gc决定要收集软引用是执行以下过程
弱引用:当gc碰到弱可及对象,并释放abcWeakRef的引用,收集该对象。但是gc可能需要对此运用才能找到该弱可及对象。
虚引用:就是没有的意思,建立虚引用之后通过get方法返回结果始终为null,通过源代码你会发现,虚引用通向会把引用的对象写进referent,只是get方法返回结果为null.先看一下和gc交互的过程在说一下他的作用.

b. 图片加载优化

尽量不要使用setImageBitmap或setImageResourceBitmapFactory.decodeResource来设置一张大图,
因为这些函数在完成decode后,最终都是通过java层的createBitmap来完成的,需要消耗更多内存。

因此,改用先通过BitmapFactory.decodeStream方法,创建出一个bitmap,再将其设为ImageView的 source,
decodeStream最大的秘密在于其直接调用JNI>>nativeDecodeAsset()来完成decode,
无需再使用java层的createBitmap,从而节省了java层的空间。
如果在读取时加上图片的Config参数,可以跟有效减少加载的内存,从而跟有效阻止抛out of Memory异常
另外,decodeStream直接拿的图片来读取字节码了, 不会根据机器的各种分辨率来自动适应,
使用了decodeStream之后,需要在hdpi和mdpi,ldpi中配置相应的图片资源,
否则在不同分辨率机器上都是同样大小(像素点数量),显示出来的大小就不对了。

1. InputStream is = this.getResources().openRawResource(R.drawable.pic1);
     BitmapFactory.Options options=new BitmapFactory.Options();
     options.inJustDecodeBounds = false;
     options.inSampleSize = 10;   //width,hight设为原来的十分一 ps.慎用会影响图片质量
     Bitmap btp =BitmapFactory.decodeStream(is,null,options);
2. if(!bmp.isRecycle() ){
         bmp.recycle()   //回收图片所占的内存
         system.gc()  //提醒系统及时回收
}
//奉上一个方法
/**
 * 以最省内存的方式读取本地资源的图片
 * @param context
 * @param resId
 * @return
 */  
 public static Bitmap readBitMap(Context context, int resId){  
   BitmapFactory.Options opt = new BitmapFactory.Options();  
   opt.inPreferredConfig = Bitmap.Config.RGB_565;   
   opt.inPurgeable = true;  
   opt.inInputShareable = true;  
   //获取资源图片  
   InputStream is = context.getResources().openRawResource(resId);  
   return BitmapFactory.decodeStream(is,null,opt);  
  }

c. 优化Dalvik虚拟机的堆内存分配
对于Android平台来说,其托管层使用的Dalvik JavaVM从目前的表现来看还有很多地方可以优化处理,
比如我们在开发一些大型游戏或耗资源的应用中可能考虑手动干涉GC处理,
使用 dalvik.system.VMRuntime类提供的setTargetHeapUtilization?方法可以增强程序堆内存的处理效率。
当然具体原理我们可以参考开源工程,这里我们仅说下使用方法: 代码如下:
private final static floatTARGET_HEAP_UTILIZATION = 0.75f;
在程序onCreate时就可以调用
VMRuntime.getRuntime().setTargetHeapUtilization?(TARGET_HEAP_UTILIZATION)

d. 自定义堆内存大小

private final static int CWJ_HEAP_SIZE = 6* 1024* 1024 ;//设置最小heap内存为6MB大小
VMRuntime.getRuntime().setMinimumHeapSize(CWJ_HEAP_SIZE);
这个方法是强制性的

总结一下:
要避免内存泄露,主要要遵循以下几点:

第一:不要为Context长期保存引用(要引用Context就要使得引用对象和它本身的生命周期保持一致)。

第二:如果要使用到Context,尽量使用ApplicationContext去代替Context,因为ApplicationContext的生命周期较长,引用情况下不会造成内存泄露问题

第三:在你不控制对象的生命周期的情况下避免在你的Activity中使用static变量。尽量使用WeakReference去代替一个static。

第四:垃圾回收器并不保证能准确回收内存,这样在使用自己需要的内容时,主要生命周期和及时释放掉不需要的对象。尽量在Activity的生命周期结束时,在onDestroy中把我们做引用的其他对象做释放,比如:cursor.close(),bitmapObject.recycle()。






posted @ 2013-04-19 17:00  鞋带松了  阅读(691)  评论(0编辑  收藏  举报