Android 图片OutOfMemory异常bitmap size exceeds VM budget的原因及解决方法

简介:

1、现象
很多朋友应该都碰到过下面这个异常

Java

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

FATAL EXCEPTION: main

java.lang.OutOfMemoryError: bitmap size exceeds VM budget

at android.graphics.BitmapFactory.nativeDecodeAsset(Native Method)

at android.graphics.BitmapFactory.nativeDecodeStream(Native Method)

at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:484)

at android.graphics.BitmapFactory.decodeFile(BitmapFactory.java:284)

at android.graphics.BitmapFactory.decodeFile(BitmapFactory.java:309)

at cn.trinea.appsearch.util.Cache$2.onImageLoaded(Cache.java:88)

at cn.trinea.appsearch.cache.ImageSDCardCache$MyHandler.handleMessage(ImageSDCardCache.java:390)

at android.os.Handler.dispatchMessage(Handler.java:99)

at android.os.Looper.loop(Looper.java:130)

at android.app.ActivityThread.main(ActivityThread.java:3703)

at java.lang.reflect.Method.invokeNative(Native Method)

at java.lang.reflect.Method.invoke(Method.java:507)

at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:841)

at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:599)

at dalvik.system.NativeStart.main(Native Method)

多图片的程序运行一段时间或是monkey test极易出现上面的异常信息,表示图片的大小超过了dalvik为程序分配的heap的大小。

2、原因
Dalvik虚拟机会为应用程序分配固定大小的heap ,如果使用超过了这个heap的大小,且没有可被回收对象,就会报oom。多张较大图片会迅速占用空间造成oom。
在Android2.3.3及之前,位图的像素存储在native memory中,在这之后的Android版本位图像素跟bitmap对象一样存储在dalvik heap中。Dalvik根据屏幕尺寸和密度决定应用程序的heap size,例如Android4.0.3的应用默认最小内存如下:

dalvik heap size 4.0.3
其他请参考 The Android Compatibility Definition Document (CDD), Section 3.7.

3、解决方法
下面介绍三种解决方法,可使用其一,推荐第一种
(1). 使用BitmapFactory.Options对图片进行缩略读取解决
oom原因是图片过大,比如尺寸2048×1536为的图片大小差不多12M,这样加载几张就会oom,但实际显示不会超过一屏,我们可以缩小长宽各缩小4倍到512×384,如此才750k而已。代码如下:

Java

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

/**

* set image src

*

* @param imageView

* @param imagePath

*/

private void setImageSrc(ImageView imageView, String imagePath) {

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

option.inSampleSize = getImageScale(imagePath);

Bitmap bm = BitmapFactory.decodeFile(imagePath, option);

imageView.setImageBitmap(bm);

}

private static int IMAGE_MAX_WIDTH = 480;

private static int IMAGE_MAX_HEIGHT = 960;

/**

* scale image to fixed height and weight

*

* @param imagePath

* @return

*/

private static int getImageScale(String imagePath) {

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

// set inJustDecodeBounds to true, allowing the caller to query the bitmap info without having to allocate the

// memory for its pixels.

option.inJustDecodeBounds = true;

BitmapFactory.decodeFile(imagePath, option);

int scale = 1;

while (option.outWidth / scale >= IMAGE_MAX_WIDTH || option.outHeight / scale >= IMAGE_MAX_HEIGHT) {

scale *= 2;

}

return scale;

}

getImageScale函数得到图片长宽均不超过最大值需要缩放的倍数,其中option.inJustDecodeBounds = true;表示仅读取图片文件信息而不为图片分配内存。

setImageSrc函数用来根据scale缩放图片设置为imageView的资源,其中option.inSampleSize表示图片长宽同时缩放的倍数。
实际可以根据屏幕的大小来缩放图片,即根据屏幕大小设置IMAGE_MAX_WIDTH和IMAGE_MAX_HEIGHT。
这段代码可以放在ImageSDCardCache的onGetSuccess中防止oom,对于ImageCache直接通过setCompressListener设置压缩比例即可。

(2). 使用SoftReference解决
使用SoftReference的好处是内存不足时,dalvik回收器可以自动回收它,这种方法就不做详细介绍,具体可见SoftReference bitmap

(3). 使用Bitmap.recycle();释放图片

告诉Dalvik可以gc时回收Bitmap,不过recycle被调用后,Bitmap不能再被操作,否则会报异常

目录
相关文章
|
4月前
|
XML JSON Java
Android App开发即时通信中通过SocketIO在客户端与服务端间传输文本和图片的讲解及实战(超详细 附源码)
Android App开发即时通信中通过SocketIO在客户端与服务端间传输文本和图片的讲解及实战(超详细 附源码)
61 0
|
17天前
|
Android开发
Android保存图片到相册(适配android 10以下及以上)
Android保存图片到相册(适配android 10以下及以上)
20 1
|
1月前
|
Android开发
[Android jni] Bitmap与Mat对象的相互转换
[Android jni] Bitmap与Mat对象的相互转换
47 0
|
3月前
|
存储 缓存 编解码
Android 性能优化: 解释Bitmap的优化策略。
Android 性能优化: 解释Bitmap的优化策略。
40 1
|
4月前
|
API Android开发
[Android]图片加载库Glide
[Android]图片加载库Glide
54 0
|
4月前
|
XML Android开发 数据格式
[Android]Bitmap Drawable
[Android]Bitmap Drawable
29 0
|
4月前
|
Android开发
[Android]制作9-Patch图片
[Android]制作9-Patch图片
42 0
|
Android开发
安卓根据需要压缩图片大小bitmap,drawable
安卓根据需要压缩图片大小bitmap,drawable
117 0
|
XML 存储 缓存
安卓 Bitmap 和 Drawable 的使用
Bitmap 的使用 高效加载大位图 解码大的 bitmap,然后加载一个较小的图片到内存中去,从而避免超出程序的内存限制。
206 0
 安卓 Bitmap 和 Drawable 的使用
|
Android开发
Android笔记:根据图片url获取bitmap或者drawable,然后再进行压缩处理
Android笔记:根据图片url获取bitmap或者drawable,然后再进行压缩处理
437 0