android outofmemory 原理及解决方案
一、問題描述:Android下的相機(jī)在獨(dú)自使用時(shí),拍照沒有問題,通過我們的代碼調(diào)用時(shí),也正常,但是更換了不同廠商的平板,ROM由Android4.0變成了Android4.1后,拍照出現(xiàn)了OutOfMemory異常,程序中斷退出。如何解決這個(gè)問題呢?
二、先看看我們之前所寫的代碼
1) 調(diào)用系統(tǒng)相機(jī)(沒有懷疑這里出錯(cuò),代碼略)
2)顯示圖片
mImageView = (ImageView) findViewById(R.id.imageView);
fileName = mData.get(0).toString();
Bitmap bitmap = BitmapFactory.decodeFile(fileName);
mImageView.setImageBitmap(bitmap);
三、問題分析
經(jīng)過調(diào)試排查,發(fā)現(xiàn)我們的bitmap圖片達(dá)到3M,如果是3K則不出錯(cuò)。啥原理呢?
四、先來看看,Android的內(nèi)存溢出是如何發(fā)生的?
Android的虛擬機(jī)是基于寄存器的Dalvik,它的最大堆大小一般是16M,有的機(jī)器為24M。因此我們所能利用的內(nèi)存空間是有限的。如果我們的內(nèi)存占用超過了一定的水平就會(huì)出現(xiàn)OutOfMemory的錯(cuò)誤。
為什么會(huì)出現(xiàn)內(nèi)存不夠用的情況呢?我想原因主要有兩個(gè):
程序本身運(yùn)行就占有一定的內(nèi)存,而程序在使用較大的bitmap時(shí),又需要一個(gè)更大的內(nèi)存空間??刂撇划?dāng),就容易造成內(nèi)OutOfMemory。
五、Android對(duì)應(yīng)用程序內(nèi)存的限制
android不同設(shè)備單個(gè)進(jìn)程可用內(nèi)存是不一樣的,可以查看/system/build.prop文件。
dalvik.vm.heapsize=24m
dalvik.vm.heapgrowthlimit=16m
可以自行對(duì)這個(gè)限制進(jìn)行更改,當(dāng)然需要先對(duì)設(shè)備進(jìn)行ROOT
六、加載位圖原理分析
1、BitmapFactory提供了幾種解碼方式(decodeByteArray(), decodeFile(), decodeResource()等等),以便從多種資源中創(chuàng)建一個(gè)Bitmap(位圖)對(duì)象??梢愿鶕?jù)你的圖片數(shù)據(jù)來源選擇最合適的解碼方式。這些方法視圖為構(gòu)造Bitmap對(duì)象分配內(nèi)存,因此很容易導(dǎo)致OutOfMemory(OOM)異常。每一種解碼方式都有額外的特征,你可以通過BitmapFactory.Options類類指定解碼方法。
2、盡量不要使用setImageBitmap或setImageResource或BitmapFactory.decodeResource直接使用圖片路徑來設(shè)置一張大圖,因?yàn)檫@些函數(shù)在完成decode后,最終都是通過java層的createBitmap來完成的,需要消耗更多內(nèi)存。改用先通過BitmapFactory.decodeStream方法,創(chuàng)建出一個(gè)bitmap,再調(diào)用上述方法將其設(shè)為ImageView的 source。decodeStream最大的秘密在于其直接調(diào)用JNI>>nativeDecodeAsset()來完成decode,無需再使用java層的createBitmap,從而節(jié)省了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.為位圖設(shè)置100K的緩存
BitmapFactory.Options opts=new BitmapFactory.Options();
opts.inTempStorage = new byte[100 * 1024];
//3.設(shè)置位圖顏色顯示優(yōu)化方式
//ALPHA_8:每個(gè)像素占用1byte內(nèi)存(8位)
//ARGB_4444:每個(gè)像素占用2byte內(nèi)存(16位)
//ARGB_8888:每個(gè)像素占用4byte內(nèi)存(32位)
//RGB_565:每個(gè)像素占用2byte內(nèi)存(16位)
//Android默認(rèn)的顏色模式為ARGB_8888,這個(gè)顏色模式色彩最細(xì)膩,顯示質(zhì)量最高。但同樣的,占用的內(nèi)存//也最大。也就意味著一個(gè)像素點(diǎn)占用4個(gè)字節(jié)的內(nèi)存。我們來做一個(gè)簡(jiǎn)單的計(jì)算題:3200*2400*4 bytes //=30M。如此驚人的數(shù)字!哪怕生命周期超不過10s,Android也不會(huì)答應(yīng)的。
opts.inPreferredConfig = Bitmap.Config.RGB_565;
//4.設(shè)置圖片可以被回收,創(chuàng)建Bitmap用于存儲(chǔ)Pixel的內(nèi)存空間在系統(tǒng)內(nèi)存不足時(shí)可以被回收
opts.inPurgeable = true;
//5.設(shè)置位圖縮放比例
//width,hight設(shè)為原來的四分一(該參數(shù)請(qǐng)使用2的整數(shù)倍),這也減小了位圖占用的內(nèi)存大小;例如,一張//分辨率為2048*1536px的圖像使用inSampleSize值為4的設(shè)置來解碼,產(chǎn)生的Bitmap大小約為//512*384px。相較于完整圖片占用12M的內(nèi)存,這種方式只需0.75M內(nèi)存(假設(shè)Bitmap配置為//ARGB_8888)。
opts.inSampleSize = 4;
//6.設(shè)置解碼位圖的尺寸信息
opts.inInputShareable = true;?
//7.解碼位圖
Bitmap btp =BitmapFactory.decodeStream(is,null, opts); ???
//8.顯示位圖
preview.setImageBitmap(bitmap);
總結(jié)
以上是生活随笔為你收集整理的android outofmemory 原理及解决方案的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 操作系统之I/O管理:2、I/O软件层次
- 下一篇: Array.prototype.slic