【移动开发】Android中图片过大造成内存溢出,OOM(OutOfMemory)异常解决方法

简介:

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

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


    这里,我将前辈们解决的方法重新整理一番,方便自己以后使用。

   1.在内存引用上做些处理,常用的有软引用、强化引用、弱引用(可以参考这篇博客:http://smallwoniu.blog.51cto.com/blog/3911954/1248751)

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

结果:

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

2.在内存中加载图片时直接在内存中做处理

  A.边界压缩

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

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

1
2
3
4
5
6
7
8
9
10
11
12
/* 自定义Adapter中部分代码*/
         public  View getView( int  position, View convertView, ViewGroup parent) {
             File file =  new  File(it. get (position));
             SoftReference<Bitmap> srf = imageCache. get (file.getName());
             Bitmap bit = srf. get ();
             ImageView i =  new  ImageView(mContext);
             i.setImageBitmap(bit);
             i.setScaleType(ImageView.ScaleType.FIT_XY);
             i.setLayoutParams(  new  Gallery.LayoutParams(WindowManager.LayoutParams.WRAP_CONTENT,
                     WindowManager.LayoutParams.WRAP_CONTENT));
             return  i;
         }

 

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

  A.第一种方式

1
2
3
4
5
6
7
8
9
InputStream  is  this .getResources().openRawResource(R.drawable.pic1);
      BitmapFactory.Options options= new  BitmapFactory.Options();
      options.inJustDecodeBounds =  false ;
      options.inSampleSize =  10 ;    //width,hight设为原来的十分一
      Bitmap btp =BitmapFactory.decodeStream( is , null ,options);
  if (!bmp.isRecycle() ){
          bmp.recycle()    //回收图片所占的内存
          system.gc()   //提醒系统及时回收
}

 

    B.第二中方式

1
2
3
4
5
6
7
8
9
10
11
12
/**
* 以最省内存的方式读取本地资源的图片
* */ 
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.在适当的时候垃圾回收

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


   D.优化Dalvik虚拟机的堆内存分配

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

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

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


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

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


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


参考博客:http://blog.sina.com.cn/s/blog_7501670601014dcj.html







     本文转自zhf651555765 51CTO博客,原文链接:http://blog.51cto.com/smallwoniu/1248875,如需转载请自行联系原作者

相关文章
|
4月前
|
XML Java Android开发
Android Studio App开发之对图片进行简单加工(包括放缩,旋转等等 附源码)
Android Studio App开发之对图片进行简单加工(包括放缩,旋转等等 附源码)
45 0
|
4月前
|
XML Java Android开发
Android Studio App开发之使用相机拍摄照片和从相册中选取图片(附源码 超详细必看)
Android Studio App开发之使用相机拍摄照片和从相册中选取图片(附源码 超详细必看)
163 0
|
7月前
|
存储 编解码 Android开发
Android关于图片方向问题
Android关于图片方向问题
41 0
|
4月前
|
XML JSON Java
Android App开发即时通信中通过SocketIO在客户端与服务端间传输文本和图片的讲解及实战(超详细 附源码)
Android App开发即时通信中通过SocketIO在客户端与服务端间传输文本和图片的讲解及实战(超详细 附源码)
60 0
|
16天前
|
Android开发
Android保存图片到相册(适配android 10以下及以上)
Android保存图片到相册(适配android 10以下及以上)
18 1
|
6月前
|
SQL 人工智能 移动开发
Android etc1tool之png图片转换pkm 和 zipalign简介
etc1tool 是一种命令行实用程序,可用于将 PNG 图片编码为 ETC1 压缩标准格式(PKM),并将 ETC1 压缩图片解码回 PNG。
|
8月前
|
Java Android开发
Android 保存资源图片到相册最新写法适用于Android10.0及以上
Android 保存资源图片到相册最新写法适用于Android10.0及以上
573 0
|
8月前
|
SQL 数据库 Android开发
Android 访问系统相册选中图片,并返回该图片的路径
Android 访问系统相册选中图片,并返回该图片的路径
95 0
|
4月前
|
API Android开发
[Android]图片加载库Glide
[Android]图片加载库Glide
54 0
|
4月前
|
Android开发
[Android]制作9-Patch图片
[Android]制作9-Patch图片
40 0