Android OOM產生原因及如何解決
OOM產生原因
OOM產生可能的原因是因為 1、載入大圖片導致記憶體溢位 2、大量記憶體洩露
OOM產生的本質是什麼呢?
Dalvik VM主要管理的記憶體 Java heap,由於手機裝置的限制,一般一個應用使用的記憶體不能超過預設值 32M(不同裝置略有差異,通過adb shell getprop | grep dalvik.vm.heapgrowthlimit命令檢視),這也就是說,當在DVM上申請的堆記憶體大於預設閥值的時候,我們的應用就會丟擲OutOfMemoryError
(其實我們會有這樣的疑問,明明我的裝置記憶體有1GB或者更大,但是這麼一張圖就OOM了?為什麼會這樣,這裡有一篇可以讓我們明白其中的原因:
如何解決和避免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問題的一些解決方案,如果大家還有其他很好的方式懇請提出來,共同提升。