天天看點

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的應用預設最小記憶體如下:

Android 圖檔OutOfMemory異常bitmap size exceeds VM budget的原因及解決方法

3、解決方法

下面介紹三種解決方法,可使用其一,推薦第一種

(1). 使用bitmapfactory.options對圖檔進行縮略讀取解決

oom原因是圖檔過大,比如尺寸2048×1536為的圖檔大小差不多12m,這樣加載幾張就會oom,但實際顯示不會超過一屏,我們可以縮小長寬各縮小4倍到512×384,如此才750k而已。代碼如下:

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

* @return

private static int getimagescale(string imagepath) {

// 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。

(2). 使用softreference解決

(3). 使用bitmap.recycle();釋放圖檔

告訴dalvik可以gc時回收bitmap,不過recycle被調用後,bitmap不能再被操作,否則會報異常

繼續閱讀