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的應用預設最小記憶體如下:
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不能再被操作,否則會報異常