当前位置: 代码迷 >> 综合 >> andorid 内存优化管理(个人总结附带图片压缩源码)
  详细解决方案

andorid 内存优化管理(个人总结附带图片压缩源码)

热度:74   发布时间:2024-01-08 22:14:47.0
本文转载这篇在网上下载到的文章,因为从本文中学到了不少关于资源优化的,并作为技术总结
红色部分表示添加上的自己看法。


tank前面做项目时遇到了一个错误:java.lang.OutOfMemoryError
我当时就没有花很多时间去处理内存这个问题。当时就以自己JAVA编程时的习惯以为像PC编程一样,自顾的一顿敲下去。
因为前面我也有做嵌入式方面的开发,当时是基于纯C的嵌入式开发,在程序开发时格外的小心指针和内存的分配,一不小心就会造成把机子内存泄露最后导致死机。
因为JAVA里没有指针,也不能像C里一样Malloc和free,JAVA是自己管理内存的分配和释放所以我一开始也不把内存放在心上,直致java.lang.OutOfMemoryError。
尤其在处理大量图像和做游戏开发时会经常碰到这类问题,所以要额外注意了。
以下我总结和归纳了下内存方面的东东,希望大家一起交流进步,有误之处请大家指正和完善。
如何优化内存管理:
1.在循环内尽量不要使用局部变量。
2.不用的对象可以把它指向NULL,并注意自己的代码质量。
3.显示让系统GC回收 (这里补充一下System.ge() 也不能随便的调用,要考虑实际情况尽量在一次耗资源操作结束后才去调用,或者有个调度的机制去判断,因为gc会占用cpu导致程式响应变慢。


if(bitmapObject.isRecycled()==false) //如果没有回收
         bitmapObject.recycle();  //http://www.cnblogs.com/tankaixiong/
4.对大型图片进行缩放有,处理图片时我们经常会用到BitmapFactory类,android系统中读取位图Bitmap时分给虚拟机中图片的堆栈大小只有8M。
用BitmapFactory解码一张图片时,有时也会遇到该错误。这往往是由于图片过大造成的。这时我们需要分配更少的内存空间来存储。
BitmapFactory.Options.inSampleSize设置恰当的inSampleSize可以使BitmapFactory分配更少的空间以消除该错误。inSampleSize的具体含义请参考SDK文档。Android提供了一种动态计算的

方法,可以去查看源码,这里不多讲。(当你仅仅只需要缩放一张图片时可以尽量的保证图片的质量而牺牲内存空间,如处理的图片比较频繁建议牺牲图像质量而保证你可以处理更多的图片,opts.inSampleSize 的计算一般都是动态计算比较多,直接给值的灵活性差。

一下一些计算方法给出供大家参考:

       /**
 *  网络版求解缩放比例法
 * @param options BitmapFactory.Options
 * @param minSideLength 最小显示区 一般赋值为 -1
 * @param maxNumOfPixels 显示区长 * 宽 的值
 * @return
 */
public static int computeSampleSize(BitmapFactory.Options options,
int minSideLength, int maxNumOfPixels) {
int initialSize = computeInitialSampleSize(options, minSideLength,
maxNumOfPixels);
int roundedSize;
if (initialSize <= 8) {
roundedSize = 1;
while (roundedSize < initialSize) {
roundedSize <<= 1;
}
} else {
roundedSize = (initialSize + 7) / 8 * 8;
}
return roundedSize;
}
private static int computeInitialSampleSize(BitmapFactory.Options options,
int minSideLength, int maxNumOfPixels) {
double w = options.outWidth;
double h = options.outHeight;
int lowerBound = (maxNumOfPixels == -1) ? 1 : (int) Math.ceil(Math
.sqrt(w * h / maxNumOfPixels));
int upperBound = (minSideLength == -1) ? 128 : (int) Math.min(
Math.floor(w / minSideLength), Math.floor(h / minSideLength));
if (upperBound < lowerBound) {
return lowerBound;
}
if ((maxNumOfPixels == -1) && (minSideLength == -1)) {
return 1;
} else if (minSideLength == -1) {
return lowerBound;
} else {
return upperBound;
}
}


        /**
*  求缩放大小的比例 自己做比较计算的到的size
* @param opts
* @param newHeight 显示高
* @param newWidth  显示宽
* @return
*/
public static int computeSampleSizeSample(BitmapFactory.Options opts, int newHeight, int newWidth){
if(opts.outHeight > newHeight || opts.outWidth > newWidth){
int insamplesizeH = opts.inSampleSize = opts.outHeight / newHeight;   // 压缩比的设置高压缩
int insamplesizeW = opts.inSampleSize = opts.outWidth / newWidth;   // 压缩比的设置宽压缩
opts.inSampleSize = opts.outHeight / newHeight;   // 压缩比的设置高压缩


if(insamplesizeW > insamplesizeH){
opts.inSampleSize = opts.outWidth / newWidth;   // 压缩比的设置宽压缩
}
}else{
opts.inSampleSize = opts.outHeight / newHeight;   // 压缩比的设置 高压缩 溢出问题
}
return opts.inSampleSize;
}


例如:
     BitmapFactory.Options opts = newBitmapFactory.Options();
    opts.inSampleSize = 4 ;
    Bitmap bitmap = BitmapFactory.decodeFile(imageFile, opts);
5.Dalvik.VMRuntime类,提供对虚拟机全局,Dalvik的特定功能的接口。
Android为每个程序分配的对内存可以通过Runtime类的 totalMemory() freeMemory() 两个方法获取VM的一些内存信息,对于系统heap内存获取,可以通过Dalvik.VMRuntime类的

getMinimumHeapSize() 方法获取最小可用堆内存,同时显示释放软引用可以调用该类的gcSoftReferences() 方法,收集可用内存。
我们还可以强制定义自己软件的对内存大小,我们使用Dalvik提供的 dalvik.system.VMRuntime类来设置最小堆内存为例:

private final static int CWJ_HEAP_SIZE = 6* 1024* 1024 ;

VMRuntime.getRuntime().setMinimumHeapSize(CWJ_HEAP_SIZE); //设置最小heap内存为6MB大小。当然对于内存吃紧来说还可以通过手动干涉GC去处理,我们将在下次提到具体应用。

使用 dalvik.system.VMRuntime类提供的setTargetHeapUtilization方法可以增强程序堆内存的处理效率。当然具体原理我们可以参考开源工程,

 这里我们仅说下使用方法:
 private final static float TARGET_HEAP_UTILIZATION = 0.75f;

在程序onCreate时就可以调用VMRuntime.getRuntime().setTargetHeapUtilization(TARGET_HEAP_UTILIZATION); 即可。

6.缓存,适量使用缓存,不要过量使用,因为内存有限,能保存路径地址的就不要存放图片数据,不经常使用的尽量不要缓存,不用时就清空。(使用完缓存后一定记得将对象赋null,便于虚拟机回收资源,同时不要重复的去new 这些缓存对象。)

7.尽量使用Android 自己一套的机制,因为android是基于Dalvik而非JVM。

 InputStream is = null;
         try {
         is = new FileInputStream(newFile(picstr));
   
         } catch (FileNotFoundException e) {
        // http://www.cnblogs.com/tankaixiong/
        // }
下面这个方法肯定优于上面这个方法。
 Resources re = mContext.getResources();
         InputStream is =re.openRawResource(picstr);

 8.补充一点一定要将java中对于文件操作的好习惯保持了对于文件流,一定要关闭,且确定不用后对象必须赋nul,资源管理就是从这一点一滴开始的。l


 

  相关解决方案