当前位置: 首页 > 图灵资讯 > 技术篇> Android有效解决加载大图片时内存溢出的问题

Android有效解决加载大图片时内存溢出的问题

来源:图灵教育
时间:2023-05-22 09:20:05

尽量不要使用setimagebitmap或setimageresource或bitmapFactory.decoderesource设置一个大图,因为这些函数最终是通过java层的createbitmap完成的,需要消耗更多的内存。因此,首先通过BitmapFactory改用.decodestream方法,创建bitmap,然后将其设置为imageview source,decodestream最大的秘密是直接调用JNI>>nativeDecodeAsset()完成decode,不需要使用java层的createBitmap,从而节省java层的空间。如果在阅读时添加图片的Config参数,可以有效减少加载内存,从而有效防止抛out of 另外,decodestream直接拿图片读取字节码, 它不会根据机器的各种分辨率自动适应, 使用decodestream后,需要hdpi和mdpi,相应的图片资源配置在ldpi中, 否则,不同分辨率机器的尺寸(像素点数)相同,显示的尺寸是错误的。此外,以下方法也很有帮助:
1.
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);
2.

if(!bmp.isRecycle() ){         bmp.recycle()   ////回收图片占用的内存         system.gc()  //及时回收提醒系统

以下是一种方法:

/**  * 以最省内存的方式读取当地资源的图片  * @param context  * @param resId  * @return  */   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);   }

================================================================================

Android内存溢出的解决方案

昨天在模拟器上给gallery放图片时,java出现了.lang.OutOfMemoryError: bitmap size exceeds VM budget 异常图像大小超过RAM内存。

模拟器RAM相对较小,只有8M内存,当我放入大量图片(每100K左右)时,就会出现上述原因。

由于每张图片以前都是压缩的,当放入Bitmap时,尺寸会变大,导致超过RAM内存,具体解决方案如下:

//解决加载图片问题 内存溢出问题

//Options 只保存图片的大小,不保存图片到内存

BitmapFactory.Options opts = new BitmapFactory.Options();

///缩放的比例很难按照准备的比例缩放。其值表示缩放的倍数。SDK建议其值为2指数值。值越大,图片就越不清晰

opts.inSampleSize = 4;

Bitmap bmp = null;

bmp = BitmapFactory.decodeResource(getResources(), mImageIds[position],opts);

...

//回收

bmp.recycle();

以上方法解决了,但这并不是最完美的解决方案。

通过一些了解,了解如下:

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

对 对于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项目来说,影响性能瓶颈的主要问题是Android自身的内存管理机制。目前,手机制造商对RAM很吝啬,RAM对软件的流畅性也很吝啬 性能的影响非常敏感,除了 除了优化Dalvik虚拟机的堆内存分配外,我们还可以强制定义我们软件的内存大小,我们使用Dalvik提供的Dalvik dalvik.system.以VMRuntime类设置最小堆内存为例:

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

VMRuntime.getRuntime().setMinimumHeapSize(CWJ_HEAP_SIZE); ///设置最小heap内存为6MB大小。当然,对于内存紧张,GC也可以手动干扰

bitmap 设置图片尺寸,避免 内存溢出 OutofmemoryEror的优化方法

★android bitmap中用 内存溢出很容易,报告如下错误:Java.lang.OutOfMemoryError : bitmap size exceeds VM budget

● 主要添加此段:

BitmapFactory.Options options = new BitmapFactory.Options();

options.inSampleSize = 2;

● eg1:(通过Uri取图)

private ImageView preview;

BitmapFactory.Options options = new BitmapFactory.Options();

options.inSampleSize = 2;//图片的宽度和高度是原来的两分之一,即图片是原来的四分之一

Bitmap bitmap = BitmapFactory.decodeStream(cr

.openInputStream(uri), null, options);

preview.setImageBitmap(bitmap);

上述代码可以优化内存溢出,但它只能改变图片的大小,不能完全解决内存溢出问题。

● eg2:(通过路径去图片)

private ImageView preview;

private String fileName= "/sdcard/DCIM/Camera/2010-05-14 16.01.44.jpg";

BitmapFactory.Options options = new BitmapFactory.Options();

options.inSampleSize = 2;//图片的宽度和高度是原来的两分之一,即图片是原来的四分之一

Bitmap b = BitmapFactory.decodeFile(fileName, options);

preview.setImageBitmap(b);

filePath.setText(fileName);

★Android 还有一些性能优化方法:

● 首先,内存可以参考 Android堆内存也可以自己定义大小 和 优化Dalvik虚拟机的堆内存分配

● 在基本类型上,由于Java没有实际的指针,它仍然需要在NDK的帮助下完成敏感操作。Android123提醒游戏开发者,谷歌更有趣 推出NDK可能是为了帮助游戏开发者,比如OpenGL ES的支持有明显的变化,需要本地代码操作图形界面。

● 图形对象优化,这里要说的是Android上的Bitmap对象被销毁,GC可以通过recycle()来回收一个Bitmap对象,通常可以使用以下方法来使用一个不需要的Bitmap,比如

if(bitmapObject.isRecycled()==false) //如果没有回收

bitmapObject.recycle();

● 目前,系统对动画的支持相对较弱。传统应用程序的间隙过渡效果是可以的,但对于游戏来说,一般艺术家可能已经习惯了GIF的统一处理。目前,Android系统只能预览GIF的第一帧,GIF89格式的资源可以通过J2ME中的线程和自写分析器来读取。

● 对于大多数Android手机来说,没有太多的物理按钮,我们可能需要想象手势识别 GestureDetector 以及重力感应来实现控制。通常要考虑误操作的降噪处理。

Android堆内存也可以自己定义大小

对于一些大型Android项目或游戏来说,除了算法处理没有问题外,影响性能瓶颈的主要问题是Android自身的内存管理机制。目前,手机制造商与RAM相比 RAM对软件的流畅性非常敏感,除了上次Android开发网提到的,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也可以手动干预。下次我们将提到具体的应用程序。

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

对 对于Android平台,其托管层使用的Dalvik 从目前的表现来看,JavaVM还有很多优化处理的地方。例如,我们可以考虑在开发一些大型游戏或资源消耗应用程序时手动干预GC处理,使用 dalvik.system.VMRuntime类提供的settargetheaputilization方法可以提高程序堆内存的处理效率。当然具体 我们可以参考开源工程的原理,这里我们只谈使用方法: private final static floatTARGET_HEAP_UTILIZATION = 0.75f; 可以在程序oncreate中调用 VMRuntime.getRuntime().setTargetHeapUtilization(TARGET_HEAP_UTILIZATION); 即可。

介绍图片占用过程中的内存算法。

Bitmap是Android中处理图片的基本类别,顾名思义,就是位图。占用内存的算法如下:

width图片*height*Config。

如果Config设置为ARGB_888,那么上面的Config是4。480*320的图片占用480*320*4的内存 byte。

前面有人说了8M的概念,其实默认情况下android过程的内存占用量是16M,因为除了java中的数据,bitmap是底层C++的。 Skia图形库还将持有Skbitmap对象,因此一般图片占用的内存推荐尺寸不应超过8m。这可以调整,并在编译源代码时设置参数。