1. 程式人生 > >Android OOM產生原因及如何解決

Android OOM產生原因及如何解決

OOM產生原因

OOM產生可能的原因是因為 1、載入大圖片導致記憶體溢位 2、大量記憶體洩露
OOM產生的本質是什麼呢?
Dalvik VM主要管理的記憶體 Java heap,由於手機裝置的限制,一般一個應用使用的記憶體不能超過預設值 32M(不同裝置略有差異,通過adb shell getprop | grep dalvik.vm.heapgrowthlimit命令檢視),這也就是說,當在DVM上申請的堆記憶體大於預設閥值的時候,我們的應用就會丟擲OutOfMemoryError
(其實我們會有這樣的疑問,明明我的裝置記憶體有1GB或者更大,但是這麼一張圖就OOM了?為什麼會這樣,這裡有一篇可以讓我們明白其中的原因:

關於Bitmap分配在native heap還是dalvik heap上的說明。,第10點有說明)。

如何解決和避免OOM

1、解決大圖片導致記憶體溢位

載入多圖:

(1)使用軟引用、弱引用,當堆記憶體不足的時候,就可以自動的釋放這些快取的Bitmap物件。

關於軟引用的說明:
軟引用(SoftReference)是用來設計object-cache的。他在JVM報告記憶體不足之前會清除所有的軟引用,這樣以來gc就有可能收集軟可及的物件,可能解決記憶體不足的問題,避免記憶體溢位。什麼時候會被收集取決於gc的演算法和gc執行時可用記憶體的大小。

關於弱應用的說明:看一個例子更容易懂:

String test =new String("aaa");       
WeakReference<String> testWeak = new WeakReference<String>(test);       
test = null;       
System.out.println("before: "+ testWeak.get());       
System.gc();       
System.out.println("after: "+ testWeak.get()); 

結果:
before: aaa
after: null
如果你希望能隨時取得某物件的資訊,但又不想影響此物件的垃圾收集,那麼你應該用 弱應用(Weak Reference)來記住此物件。

(2)使用過的圖並且不再使用,可以呼叫Bitmap.recycle()加速回收。

if (null != bitmap && !bitmap.isRecycled()) {  
    bitmap.recycle();  
}  

(3)考慮使用檔案快取。

整個大圖都需要載入:

得到bitmap之前先利用BitmapFactory.Options的inSampleSize的值得到壓縮圖片。
關鍵程式碼:

    // 第一次解析將inJustDecodeBounds設定為true,來獲取圖片大小 
    final BitmapFactory.Options options = new BitmapFactory.Options(); 
    options.inJustDecodeBounds = true; 
    BitmapFactory.decodeResource(res, resId, options); 
    // 呼叫上面定義的方法計算inSampleSize值, calculateInSampleSize方法自己寫,這裡不再贅述
    options.inSampleSize = calculateInSampleSize(options.outWidth, options.outHeight, reqWidth, reqHeight);

    options.inJustDecodeBounds = false; 
    Bitmap bmp = BitmapFactory.decodeResource(res, resId, options); 

只加載部分圖片

可以考慮在API 10以後引進的BitmapRegionDecoder類,具體使用方式還未研究,原始碼註釋(BitmapRegionDecoder is particularly useful when an original image is large and you only need parts of the image)。

2、解決記憶體洩露問題

解決該問題主要需要對Android系統各部分元件進行一些較深入瞭解,比如:
對Activity的生命週期進行了解以後,就應該避免對生命週期之外的引用。一個應用可能有多個Activity構成,這時候應該考慮使用Application類。(該問題主要是針對Activity中靜態物件的控制)
儘量不要由於各種複雜的引用導致GC不能及時的甚至永遠不能回收某塊記憶體。

以上是我對OOM問題的一些解決方案,如果大家還有其他很好的方式懇請提出來,共同提升。