android 图片 oom,Android-加载图片OOM总结

setImageBitmap或setImageResource或BitmapFactory.decodeResource来设置一张大图,这些函数在完成decode后,最终都是通过java层的createBitmap来完成的,需要消耗更多的内存。

改用先通过BitmapFactory.decodeStream方法,创建出一个bitmap,再将其设为ImageView的source

decodeStream最大的好处在于其直接调用JNI  的nativeDecodeAsset()来完成decode,无需再使用java层的createBitmap,从而节省了java层的空间

如果在读取时加上图片的Config参数,可以更有效减少加载的内存,从而更有效避免out of memory的异常

另外,decodeStream直接拿图片来读取字节码,不会根据机器的各种分辨率来自动适应,使用了decodeStream之后,需要配置相应大小的图片资源

默认情况下android进程的内存占用量为16M,因为bitmap他除了java中持有数据外,底层C++的skia图形库还会持有一个SKBitmap对象,因此一般图片占用内存推荐大小应该不超过8M

1、BitmapFactory.Options

inPreferredConfig 指定decode到内存中,手机中所采用的编码,可选值定义在Bitmap.Config中。缺省值是ARGB_8888。可以使ALPHA_8、ARGB_444、ARGB_8888、RGB_565                                               bitmap占用内存的算法如下:图片的width*height*Config                                                                                                                                                                                                                                             如果config设置为ARGB_8888,那么上面的Config为4,也就是4个字节的意思。一张480*320的图片占用的内存就是480*320*4byte。

inJustDecodeBounds 如果设置为true,并不会把图像的数据完全解码,亦即decodeXyz()返回值为null,但是Options的outAbc中解出了图像的基本信息。

inSampleSize 设置decode时的缩放比例。

inPurgeable设为true的话表示使用BitmapFactory创建的Bitmap用于存储Pixel的内存空间在系统内存不足时可以被回收,在应用需要再次访问bitmap的Pixel时,系统会再次条用BitmapFactory decoder重新生成Bitmap的Pixel数组,为了能够重新解码图像,bitmap要能够访问存储bitmap的原始数据。在inPugeable为false时表示创建bitmap的pixel内存空间不能被回收,这样bitmapfactory在不停decodeByteArray创建新的Bitmap对象,不同设备的内存不同,因此能够同时创建的Bitmap个数可能有所不同,200个bitmap足以使大部分的设备出现OutOfMemory错误。当inPurgeable设为true时,系统中内存不足时,可以回收部分bitmap占据的内存空间,这时一般不会出现OutOfMemory错误

inInputShareable是否深拷贝

2、以最省内存的方式读取本地资源的图片

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

options.inInputShareable = true;

options.inPurgeable = true;

options.inJustDecodeBounds = false;

options.inPreferredConfig = Bitmap.Config.RGB_565;

options.inSampleSize = 3; // width,hight设为原来的1/3

//获取资源图片流

InputStream is = context.getResources().openRawResource(resId);

BitmapFactory.decodeStream(is,null,options);

3、最近解决bitmap加载时out of memory的心得

游戏在加载背景图片

要么挂在BitmapFactory. decodeStream( assets.open(path));

要么挂在surface = Bitmap.createBitmap (surface , 0, 0,

surface.getWidth(),surface .getHeight(), matrix,true);

0818b9ca8b590ca3270a3433284dd417.png第一次尝试:看到图片是png格式的,将图片转为jpg。图片大小减少了不少。不过没多大效果。

原因:虽然改为jpg,加载时存储的方式会默认为ARGB_565,本来是png为ARGB_8888,占用内存会减少一半。不过开销还是很大,用createBitmap放大时,改方法是java层的实现,效率太差。

0818b9ca8b590ca3270a3433284dd417.png第二次尝试:想到cocos2d-x的瓦片地图,所以将背景图片分割为9份(自己用ps切),有些效果,不会每次切换场景都会挂,但是很多的征战地图,没全部切,所以当进入没切的场景时,还是会挂。

原因:没有找到问题的源头,变小图了,加载时开销的内存确实减少不少。不过太多场景都去切不太实际,这样程序改变很大。可能会出现bug的风险。

0818b9ca8b590ca3270a3433284dd417.png第三次尝试:配置BitmapFactory.Config的属性,使用(2)中的方式读取图片,省去createBitmap去放大图片,使用两套资源,在这些屏幕上用大图。成功解决问题。

原因:都用了BitmapFactory.decodeStream方法读取图片,该方法直接使用native方法,用c++实现。效率果然是高。虽然当时还不知道这个原因。今天总结的时候通过源代码才理解。

例子:

1、图片加载超过20M,直接程序崩溃

10-10 17:58:39.940: E/dalvikvm(14548): GC_FOR_ALLOC freed 79K, 13% free 35752K/40647K, paused 15ms+6ms, total 84ms

10-10 17:58:40.000: E/dalvikvm(14548): GC_BEFORE_OOM freed 12K, 13% free 35740K/40647K, paused 64ms, total 64ms

10-10 17:58:40.000: E/dalvikvm-heap(14548): Out of memory on a 20155408-byte allocation.

错误做法:

setImageBitmap或setImageResource或BitmapFactory.decodeResource来设置一张大图

Drawable.createFromPath

正确做法:

用上面 ”以最省内存的方式读取本地资源的图片”的方法!!!

2. if(!bmp.isRecycle() ){

bmp.recycle()   //回收图片所占的内存

system.gc()  //提醒系统及时回收

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值