1. 程式人生 > >點陣圖引起的記憶體溢位OutOfMemory解決方案

點陣圖引起的記憶體溢位OutOfMemory解決方案

點陣圖引起的記憶體溢位OutOfMemory解決方案

作者:老帥

一、問題描述:Android下的相機在獨自使用時,拍照沒有問題,通過我們的程式碼呼叫時,也正常,但是更換了不同廠商的平板,ROM由Android4.0變成了Android4.1後,拍照出現了OutOfMemory異常,程式中斷退出。如何解決這個問題呢?

二、先看看我們之前所寫的程式碼

1) 呼叫系統相機(沒有懷疑這裡出錯,程式碼略)

2)顯示圖片

mImageView = (ImageView) findViewById(R.id.imageView);

fileName = mData.get(0).toString();

Bitmap bitmap = BitmapFactory.decodeFile(fileName);

mImageView.setImageBitmap(bitmap);

三、問題分析

經過除錯排查,發現我們的bitmap圖片達到3M,如果是3K則不出錯。啥原理呢?

四、先來看看,Android的記憶體溢位是如何發生的?

Android的虛擬機器是基於暫存器的Dalvik,它的最大堆大小一般是16M,有的機器為24M。因此我們所能利用的記憶體空間是有限的。如果我們的記憶體佔用超過了一定的水平就會出現OutOfMemory的錯誤。

為什麼會出現記憶體不夠用的情況呢?我想原因主要有兩個:

程式本身執行就佔有一定的記憶體,而程式在使用較大的bitmap時,又需要一個更大的記憶體空間。控制不當,就容易造成內OutOfMemory

五、Android對應用程式記憶體的限制

android不同裝置單個程序可用記憶體是不一樣的,可以檢視/system/build.prop檔案。

dalvik.vm.heapsize=24m

dalvik.vm.heapgrowthlimit=16m

可以自行對這個限制進行更改,當然需要先對裝置進行ROOT

六、載入點陣圖原理分析

1BitmapFactory提供了幾種解碼方式(decodeByteArray(), decodeFile(), decodeResource()等等),以便從多種資源中建立一個Bitmap(點陣圖)物件。可以根據你的圖片資料來源選擇最合適的解碼方式。這些方法檢視為構造Bitmap

物件分配記憶體,因此很容易導致OutOfMemory(OOM)異常。每一種解碼方式都有額外的特徵,你可以通過BitmapFactory.Options類類指定解碼方法。

2、儘量不要使用setImageBitmapsetImageResourceBitmapFactory.decodeResource直接使用圖片路徑來設定一張大圖,因為這些函式在完成decode後,最終都是通過java層的createBitmap來完成的,需要消耗更多記憶體。改用先通過BitmapFactory.decodeStream方法,創建出一個bitmap,再呼叫上述方法將其設為ImageView sourcedecodeStream最大的祕密在於其直接呼叫JNI>>nativeDecodeAsset()來完成decode,無需再使用java層的createBitmap,從而節省了java層的空間。下面是使用InputStream載入圖片的幾種方法:

方法一、載入資原始檔中指定的圖片

InputStream is = getResources().openRawResource(R.drawable.temp);

方法二、載入assest目錄下的圖片

AssetManager asm=getAssetMg();

InputStream is=asm.open(name);//name:圖片的名稱

方法三、載入SD卡目錄下的圖片

String path =Environment.getExternalStorageDirectory().toString()+ "/DCIM/device.png";

inputStream is = new FileInputStream(path)

七、解決方案

private ImageView preview;

//1.載入點陣圖

String path = Environment.getExternalStorageDirectory().toString()+"/DCIM/device.png";

inputStream is = new FileInputStream(path)

//2.為點陣圖設定100K的快取

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

opts.inTempStorage = new byte[100 * 1024];

//3.設定點陣圖顏色顯示優化方式

//ALPHA_8:每個畫素佔用1byte記憶體(8位)

//ARGB_4444:每個畫素佔用2byte記憶體16位)

//ARGB_8888:每個畫素佔用4byte記憶體32位)

//RGB_565:每個畫素佔用2byte記憶體16位)

//Android預設的顏色模式為ARGB_8888,這個顏色模式色彩最細膩,顯示質量最高。但同樣的,佔用的記憶體//也最大。也就意味著一個畫素點佔用4個位元組的記憶體。我們來做一個簡單的計算題:3200*2400*4 bytes //=30M。如此驚人的數字!哪怕生命週期超不過10sAndroid也不會答應的。

opts.inPreferredConfig = Bitmap.Config.RGB_565;

//4.設定圖片可以被回收,建立Bitmap用於儲存Pixel的記憶體空間在系統記憶體不足時可以被回收

opts.inPurgeable = true;

//5.設定點陣圖縮放比例

//widthhight設為原來的四分一(該引數請使用2的整數倍),這也減小了點陣圖佔用的記憶體大小;例如,一張//解析度為2048*1536px的影象使用inSampleSize值為4的設定來解碼,產生的Bitmap大小約為//512*384px。相較於完整圖片佔用12M的記憶體,這種方式只需0.75M記憶體(假設Bitmap配置為//ARGB_8888)

opts.inSampleSize = 4;

//6.設定解碼點陣圖的尺寸資訊

opts.inInputShareable = true; 

//7.解碼點陣圖

Bitmap btp =BitmapFactory.decodeStream(is,null, opts);    

//8.顯示點陣圖

preview.setImageBitmap(bitmap);