由于android设备的RAM较小,且Java的GC机制不够智能,经常会出现Out of memory异常。 当然,除了上面的原因,也有可能就是因为写的程序有bug,产生内存溢出。在进行图片较多的软件处理时,很有可能会遇到OOM(out of memory)的异常。
图片是一个非常消耗内存的资源,针对图片的处理需要进行特殊的处理。经过一段时间的调研,我总结出来几个注意事项。
-  尽量使用9png格式的图片
-  加载图片时,压缩图片后加载
-  尽快的手动标记回收图片资源
-  设置dalivk虚拟机的初始堆内存大小和GC效率(适用于不单单是图片的问题)
-  调用system.gc来执行垃圾回收(不赞成的方法)
下面是对这几个内容的仔细分析:
    android系统为了提高图片的质量,提高android对各种屏幕的适应能力。系统推出了对.9.png格式图片的支持。这就就可以把一些图片在美工那里就做的非常小,之后还满足了产品对品质的要求。
    正常程序中加载图片调用函数:BitmapFactory.decodeFile(imageFile);
    为了在加载图片时可以对图片压缩后在加载,对前面的这段代码进行一下加工:
| 1 | BitmapFactory.Options opts = newBitmapFactory.Options(); | 
 
| 2 | opts.inJustDecodeBounds = true; | 
 
| 3 | Bitmap bitmap = BitmapFactory.decodeFile(imageFile, opts); | 
 
 
 
    设置inJustDecodeBounds为true后,decodeFile并不分配空间,但可计算出原始图片的长度和宽度,即opts.width和opts.height。有了这两个参数,再通过一定的算法,即可得到一个恰当的inSampleSize。
    查看Android源码,Android提供了一种动态计算的方法。
| 01 | publicstaticintcomputeSampleSize(BitmapFactory.Options options, | 
 
| 02 |         intminSideLength, intmaxNumOfPixels) { | 
 
| 03 |     intinitialSize = computeInitialSampleSize(options, minSideLength, | 
 
| 07 |     if(initialSize <= 8) { | 
 
| 09 |         while(roundedSize < initialSize) { | 
 
| 13 |         roundedSize = (initialSize + 7) / 8* 8; | 
 
| 19 | privatestaticintcomputeInitialSampleSize(BitmapFactory.Options options, | 
 
| 20 |         intminSideLength, intmaxNumOfPixels) { | 
 
| 21 |     doublew = options.outWidth; | 
 
| 22 |     doubleh = options.outHeight; | 
 
| 24 |     intlowerBound = (maxNumOfPixels == -1) ? 1: | 
 
| 25 |             (int) Math.ceil(Math.sqrt(w * h / maxNumOfPixels)); | 
 
| 26 |     intupperBound = (minSideLength == -1) ? 128: | 
 
| 27 |             (int) Math.min(Math.floor(w / minSideLength), | 
 
| 28 |             Math.floor(h / minSideLength)); | 
 
| 30 |     if(upperBound < lowerBound) { | 
 
| 35 |     if((maxNumOfPixels == -1) && | 
 
| 36 |             (minSideLength == -1)) { | 
 
| 38 |     } elseif(minSideLength == -1) { | 
 
 
 
     使用该算法,就可动态计算出图片的inSampleSize。然后去设置好inSampleSize后才去加载图片。
          //解决加载图片 内存溢出的问题 
                //Options 只保存图片尺寸大小,不保存图片到内存 
                BitmapFactory.Options opts = new BitmapFactory.Options(); 
                //缩放的比例,缩放是很难按准备的比例进行缩放的,其值表明缩放的倍数,SDK中建议其值是2的指数值,值越大会导致图片不清晰 
                opts.inSampleSize = 4; 
                Bitmap bmp = null; 
                bmp = BitmapFactory.decodeResource(getResources(), mImageIds[position],opts); 
 
  
    在图片资源用完时,尽量手动的去标记一下这些已经用完的图片。帮助GC去识别不用的图片,并回收。
   
if(bitmapObject.isRecycled()==false) //如果没有回收   
         bitmapObject.recycle();   
 
  
- 设置dalivk虚拟机的初始堆内存大小和GC效率(适用于不单单是图片的问题)
    对于Android平台来说,其托管层使用的Dalvik Java VM从目前的表现来看还有很多地方可以优化处理,比如我们在开发一些大型游戏或耗资源的应用中可能考虑手动干涉GC处理,使用 dalvik.system.VMRuntime类提供的setTargetHeapUtilization方法可以增强程序堆内存的处理效率。当然具体 原理我们可以参考开源工程,这里我们仅说下使用方法:   private final static float TARGET_HEAP_UTILIZATION = 0.75f; 在程序onCreate时就可以调用VMRuntime.getRuntime().setTargetHeapUtilization(TARGET_HEAP_UTILIZATION); 即可。 
 
      对于一些Android项目,影响性能瓶颈的主要是Android自己内存管理机制问题,目前手机厂商对RAM都比较吝啬,对于软件的流畅性来说RAM对 性能的影响十分敏感,除了 优化Dalvik虚拟机的堆内存分配外,我们还可以强制定义自己软件的对内存大小,我们使用Dalvik提供的 dalvik.system.VMRuntime类来设置最小堆内存为例: 
private final static int CWJ_HEAP_SIZE = 6* 1024* 1024 ; 
VMRuntime.getRuntime().setMinimumHeapSize(CWJ_HEAP_SIZE); //设置最小heap内存为6MB大小。当然对于内存吃紧来说还可以通过手动干涉GC去处理 
 
- 调用system.gc来执行垃圾回收(不赞成的方法)
    在以上功能均不能满足条件时,考虑使用该方法。