由于android設備的RAM較小,且Java的GC機制不夠智能,經(jīng)常會出現(xiàn)Out of memory異常。 當然,除了上面的原因,也有可能就是因為寫的程序有bug,產(chǎn)生內(nèi)存溢出。在進行圖片較多的軟件處理時,很有可能會遇到OOM(out of memory)的異常。
圖片是一個非常消耗內(nèi)存的資源,針對圖片的處理需要進行特殊的處理。經(jīng)過一段時間的調(diào)研,我總結(jié)出來幾個注意事項。
- 盡量使用9png格式的圖片
- 加載圖片時,壓縮圖片后加載
- 盡快的手動標記回收圖片資源
- 設置dalivk虛擬機的初始堆內(nèi)存大小和GC效率(適用于不單單是圖片的問題)
- 調(diào)用system.gc來執(zhí)行垃圾回收(不贊成的方法)
下面是對這幾個內(nèi)容的仔細分析:
android系統(tǒng)為了提高圖片的質(zhì)量,提高android對各種屏幕的適應能力。系統(tǒng)推出了對.9.png格式圖片的支持。這就就可以把一些圖片在美工那里就做的非常小,之后還滿足了產(chǎn)品對品質(zhì)的要求。
正常程序中加載圖片調(diào)用函數(shù):BitmapFactory.decodeFile(imageFile);
為了在加載圖片時可以對圖片壓縮后在加載,對前面的這段代碼進行一下加工:
1 | BitmapFactory.Options opts = new BitmapFactory.Options(); |
2 | opts.inJustDecodeBounds = true ; |
3 | Bitmap bitmap = BitmapFactory.decodeFile(imageFile, opts); |
設置inJustDecodeBounds為true后,decodeFile并不分配空間,但可計算出原始圖片的長度和寬度,即opts.width和opts.height。有了這兩個參數(shù),再通過一定的算法,即可得到一個恰當?shù)膇nSampleSize。
查看Android源碼,Android提供了一種動態(tài)計算的方法。
01 | public static int computeSampleSize(BitmapFactory.Options options, |
02 | int minSideLength, int maxNumOfPixels) { |
03 | int initialSize = computeInitialSampleSize(options, minSideLength, |
07 | if (initialSize <= 8 ) { |
09 | while (roundedSize < initialSize) { |
13 | roundedSize = (initialSize + 7 ) / 8 * 8 ; |
19 | private static int computeInitialSampleSize(BitmapFactory.Options options, |
20 | int minSideLength, int maxNumOfPixels) { |
21 | double w = options.outWidth; |
22 | double h = options.outHeight; |
24 | int lowerBound = (maxNumOfPixels == - 1 ) ? 1 : |
25 | ( int ) Math.ceil(Math.sqrt(w * h / maxNumOfPixels)); |
26 | int upperBound = (minSideLength == - 1 ) ? 128 : |
27 | ( int ) Math.min(Math.floor(w / minSideLength), |
28 | Math.floor(h / minSideLength)); |
30 | if (upperBound < lowerBound) { |
31 | // return the larger one when there is no overlapping zone. |
35 | if ((maxNumOfPixels == - 1 ) && |
36 | (minSideLength == - 1 )) { |
38 | } else if (minSideLength == - 1 ) { |
使用該算法,就可動態(tài)計算出圖片的inSampleSize。然后去設置好inSampleSize后才去加載圖片。
//解決加載圖片 內(nèi)存溢出的問題
//Options 只保存圖片尺寸大小,不保存圖片到內(nèi)存
BitmapFactory.Options opts = new BitmapFactory.Options();
//縮放的比例,縮放是很難按準備的比例進行縮放的,其值表明縮放的倍數(shù),SDK中建議其值是2的指數(shù)值,值越大會導致圖片不清晰
opts.inSampleSize = 4;
Bitmap bmp = null;
bmp = BitmapFactory.decodeResource(getResources(), mImageIds[position],opts);
在圖片資源用完時,盡量手動的去標記一下這些已經(jīng)用完的圖片。幫助GC去識別不用的圖片,并回收。
if(bitmapObject.isRecycled()==false) //如果沒有回收
bitmapObject.recycle();
- 設置dalivk虛擬機的初始堆內(nèi)存大小和GC效率(適用于不單單是圖片的問題)
對于Android平臺來說,其托管層使用的Dalvik Java VM從目前的表現(xiàn)來看還有很多地方可以優(yōu)化處理,比如我們在開發(fā)一些大型游戲或耗資源的應用中可能考慮手動干涉GC處理,使用 dalvik.system.VMRuntime類提供的setTargetHeapUtilization方法可以增強程序堆內(nèi)存的處理效率。當然具體 原理我們可以參考開源工程,這里我們僅說下使用方法: private final static float TARGET_HEAP_UTILIZATION = 0.75f; 在程序onCreate時就可以調(diào)用VMRuntime.getRuntime().setTargetHeapUtilization(TARGET_HEAP_UTILIZATION); 即可。
對于一些Android項目,影響性能瓶頸的主要是Android自己內(nèi)存管理機制問題,目前手機廠商對RAM都比較吝嗇,對于軟件的流暢性來說RAM對 性能的影響十分敏感,除了 優(yōu)化Dalvik虛擬機的堆內(nèi)存分配外,我們還可以強制定義自己軟件的對內(nèi)存大小,我們使用Dalvik提供的 dalvik.system.VMRuntime類來設置最小堆內(nèi)存為例:
private final static int CWJ_HEAP_SIZE = 6* 1024* 1024 ;
VMRuntime.getRuntime().setMinimumHeapSize(CWJ_HEAP_SIZE); //設置最小heap內(nèi)存為6MB大小。當然對于內(nèi)存吃緊來說還可以通過手動干涉GC去處理
- 調(diào)用system.gc來執(zhí)行垃圾回收(不贊成的方法)
在以上功能均不能滿足條件時,考慮使用該方法。
本站僅提供存儲服務,所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權內(nèi)容,請
點擊舉報。