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

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

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

 

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

 

01.importjava.lang.ref.PhantomReference;

02.importjava.lang.ref.Reference; 03.importjava.lang.ref.ReferenceQueue; 04.importjava.lang.reflect.Field; 05.publicclass Test { 06.    publicstatic boolean isRun = true; 07.    publicstatic void main(String[] args) throws Exception { 08.        String abc =new String("abc"); 09.        System.out.println(abc.getClass() +"@" + abc.hashCode()); 10.                                                                                                                                                                                                                                                                                                                                                                                                                  11.        finalReferenceQueue referenceQueue = newReferenceQueue<String>(); 12.        newThread() { 13.            publicvoid 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.privateBitmap 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.    intoutWidth  = bitmapFactoryOptions.outWidth; 09.    intoutHeight = bitmapFactoryOptions.outHeight; 10.    bmap = BitmapFactory.decodeFile(picture.getAbsolutePath(), 11.         bitmapFactoryOptions); 12.    floatimagew = 150; 13.    floatimageh = 150; 14.    intyRatio = (int) Math.ceil(bitmapFactoryOptions.outHeight 15.            / imageh); 16.    intxRatio = (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.        returnbmap; 32.    } 33.    returnnull; 34.}    

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

01./* 自定义Adapter中部分代码*/02.        publicView 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.            returni; 12.        }

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


  A.第一种方式

01.InputStream is =this.getResources().openRawResource(R.drawable.pic1);02.     BitmapFactory.Options options=newBitmapFactory.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.publicstatic 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.           returnBitmapFactory.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.privatefinal 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.privatefinal 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