Android中图片过大造成内存溢出,OOM(OutOfMemory)异常解决方法(1)

当我们在做项目过程中,一遇到显示图片时,就要考虑图片的大小,所占内存的大小,原因就是 Android分配给Bitmap的大小只有8M,试想想我们用手机拍照,普通的一张照片不也得1M以上,所以android处理图片时不得不考虑图片过大造成的内存异常。

   那时候只是简单地缓存图片到本地 然后将图片进行压缩,但是感觉这个问题没有很好的解决办法,只是减小了发生的几率

 

这里,我将前辈们解决的方法重新整理一番,方便自己以后使用。
   1.在内存引用上做些处理,常用的有软引用、强化引用、弱引用

 

01.import java.lang.ref.PhantomReference;

02. import java.lang.ref.Reference;
03. import java.lang.ref.ReferenceQueue;
04. import java.lang.reflect.Field;
05. public class Test {
06.     public static boolean isRun = true;
07.     public static void main(String[] args) throws Exception {
08.         String abc = new String("abc");
09.         System.out.println(abc.getClass() + "@" + abc.hashCode());
10.                                                                                                                                                                                                                                                                                                                                                                                                                  
11.         final ReferenceQueue referenceQueue = new ReferenceQueue<String>();
12.         new Thread() {
13.             public void run() {
14.                 while (isRun) {
15.                     Object o = referenceQueue.poll();
16.                     if (o != null) {
17.                         try {
18.                             Field rereferent = Reference.class
19.                                     .getDeclaredField("referent");
20.                             rereferent.setAccessible(true);
21.                             Object result = rereferent.get(o);
22.                             System.out.println("gc will collect:"
23.                                     + result.getClass() + "@"
24.                                     + result.hashCode());
25.                         } catch (Exception e) {
26.                             e.printStackTrace();
27.                         }
28.                     }
29.                 }
30.             }
31.         }.start();
32.         PhantomReference<String> abcWeakRef = new PhantomReference<String>(abc,
33.                 referenceQueue);
34.         abc = null;
35.         Thread.currentThread().sleep(3000);
36.         System.gc();
37.         Thread.currentThread().sleep(3000);
38.         isRun = false;
39.     }
40. }

结果:

class java.lang.String@96354
gc will collect:class java.lang.String@96354

 

2.在内存中加载图片时直接在内存中做处理
  A.边界压缩

01.@SuppressWarnings("unused")

02. private Bitmap copressImage(String imgPath){
03.     File picture = new File(imgPath);
04.     Options bitmapFactoryOptions = new BitmapFactory.Options();
05.     //下面这个设置是将图片边界不可调节变为可调节
06.     bitmapFactoryOptions.inJustDecodeBounds = true;
07.     bitmapFactoryOptions.inSampleSize = 2;
08.     int outWidth  = bitmapFactoryOptions.outWidth;
09.     int outHeight = bitmapFactoryOptions.outHeight;
10.     bmap = BitmapFactory.decodeFile(picture.getAbsolutePath(),
11.          bitmapFactoryOptions);
12.     float imagew = 150;
13.     float imageh = 150;
14.     int yRatio = (int) Math.ceil(bitmapFactoryOptions.outHeight
15.             / imageh);
16.     int xRatio = (int) Math
17.             .ceil(bitmapFactoryOptions.outWidth / imagew);
18.     if (yRatio > 1 || xRatio > 1) {
19.         if (yRatio > xRatio) {
20.             bitmapFactoryOptions.inSampleSize = yRatio;
21.         } else {
22.             bitmapFactoryOptions.inSampleSize = xRatio;
23.         }
24.                                                                                                                                                                                                                                                      
25.     
26.     bitmapFactoryOptions.inJustDecodeBounds = false;//false --- allowing the caller to query the bitmap without having to allocate the memory for its pixels.
27.     bmap = BitmapFactory.decodeFile(picture.getAbsolutePath(),
28.             bitmapFactoryOptions);
29.     if(bmap != null){               
30.         //ivwCouponImage.setImageBitmap(bmap);
31.         return bmap;
32.     }
33.     return null;
34. }
 
 

B.边界压缩的情况下间接的使用了软引用来避免OOM

01. /* 自定义Adapter中部分代码*/
02.         public View getView(int position, View convertView, ViewGroup parent) {
03.             File file = new File(it.get(position));
04.             SoftReference<Bitmap> srf = imageCache.get(file.getName());
05.             Bitmap bit = srf.get();
06.             ImageView i = new ImageView(mContext);
07.             i.setImageBitmap(bit);
08.             i.setScaleType(ImageView.ScaleType.FIT_XY);
09.             i.setLayoutParams( new Gallery.LayoutParams(WindowManager.LayoutParams.WRAP_CONTENT,
10.                     WindowManager.LayoutParams.WRAP_CONTENT));
11.             return i;
12.         }

    但大家都知道,这些函数在完成decode后,最终都是通过java层的createBitmap来完成的,需要消耗更多内存,如果图片多且大,这种方式还是会引用OOM异常的,因此需要进一步处理:


  A.第一种方式

01. InputStream is = this.getResources().openRawResource(R.drawable.pic1);
02.      BitmapFactory.Options options=new BitmapFactory.Options();
03.      options.inJustDecodeBounds = false;
04.      options.inSampleSize = 10;   //width,hight设为原来的十分一
05.      Bitmap btp =BitmapFactory.decodeStream(is,null,options);
06.  if(!bmp.isRecycle() ){
07.          bmp.recycle()   //回收图片所占的内存
08.          system.gc()  //提醒系统及时回收
09. }
 
 

B.第二中方式

01. /**
02. * 以最省内存的方式读取本地资源的图片
03. * */  
04. public static Bitmap readBitMap(Context context, int resId){  
05.         BitmapFactory.Options opt = new BitmapFactory.Options();  
06.         opt.inPreferredConfig = Bitmap.Config.RGB_565;   
07.        opt.inPurgeable = true;  
08.        opt.inInputShareable = true;  
09.           //获取资源图片  
10.        InputStream is = context.getResources().openRawResource(resId);  
11.            return BitmapFactory.decodeStream(is,null,opt);  
12.    }
 
 

C.在适当的时候垃圾回收

1. if(bitmapObject.isRecycled()==false) //如果没有回收  
2.          bitmapObject.recycle();

   D.优化Dalvik虚拟机的堆内存分配
    对于Android平台来说,其托管层使用的Dalvik JavaVM从目前的表现来看还有很多地方可以优化处理,eg我们在开发一些大型游戏或耗资源的应用中可能考虑手动干涉GC处理,使用 dalvik.system.VMRuntime类提供的setTargetHeapUtilization方法可以增强程序堆内存的处理效率。

1. private final static floatTARGET_HEAP_UTILIZATION = 0.75f; 
2. //在程序onCreate时就可以调用
3. VMRuntime.getRuntime().setTargetHeapUtilization(TARGET_HEAP_UTILIZATION);
4. 即可

  至于上面为何是0.75,是因为堆(HEAP)是VM中占用内存最多的部分,通常是动态分配的。堆的大小不是一成不变的,通常有一个分配机制来控制它的大小。比如初始的HEAP是4M大,当4M的空间被占用超过75%的时候,重新分配堆为8M大;当8M被占用超过75%,分配堆为16M大。倒过来,当16M的堆利用不足30%的时候,缩减它的大小为8M大。重新设置堆的大小,尤其是压缩,一般会涉及到内存的拷贝,所以变更堆的大小对效率有不良影响。


E.自定义我们的应用需要多大的内存

1. private final static int CWJ_HEAP_SIZE = 6* 1024* 1024 ;
2.  //设置最小heap内存为6MB大小
3. VMRuntime.getRuntime().setMinimumHeapSize(CWJ_HEAP_SIZE);

以上这些就是本人总结的一些解决OOM异常的方法,希望能帮助到大家!

 

http://www.it165.net/pro/html/201307/6463.html
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值