首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計綜合問答

Android 程式發生 OutOfMemoryError 錯誤?教你如何釋放 Bitmap 記憶體解決崩潰問題

     編輯:程式設計綜合問答

在 Android 開發中,java.lang.OutOfMemoryError 是最讓開發者頭痛的錯誤之一。特別是當應用程式在處理圖片時突然崩潰,Logcat 吐出一長串堆疊追蹤,指向 BitmapFactory.nativeDecodeStream 或 decodeFile 等方法,這通常意味著記憶體不足以載入該圖片。

錯誤原因深度解析

從堆疊追蹤可以看出,錯誤發生在 Activity.dispatchActivityResult 階段,說明問題出在從相機或相簿選取圖片返回時。Android 系統為每個應用分配的記憶體有限(早期裝置僅 16MB-24MB),而未經壓縮的高解析度圖片極易超過此限制。當 BitmapFactory 嘗試將圖片解碼載入記憶體時,若可用記憶體不足,便會拋出 OOM 錯誤。

核心解決方案:及時回收 Bitmap

最佳回答指出:「在每張圖片處理完後,對 bitmap 進行回收就 OK 了。」這是解決問題的關鍵。具體實作步驟如下:

1. 使用 inSampleSize 進行縮放載入

public static Bitmap decodeSampledBitmapFromFile(String path, int reqWidth, int reqHeight) {
    // 先解碼邊界獲取原始尺寸
    final BitmapFactory.Options options = new BitmapFactory.Options();
    options.inJustDecodeBounds = true;
    BitmapFactory.decodeFile(path, options);

    // 計算縮放比例
    options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);

    // 真正解碼載入縮放後的圖片
    options.inJustDecodeBounds = false;
    return BitmapFactory.decodeFile(path, options);
}

public static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {
    if (reqWidth == 0 || reqHeight == 0) return 1;
    int inSampleSize = 1;
    if (options.outHeight > reqHeight || options.outWidth > reqWidth) {
        final int halfHeight = options.outHeight / 2;
        final int halfWidth = options.outWidth / 2;
        while ((halfHeight / inSampleSize) >= reqHeight && (halfWidth / inSampleSize) >= reqWidth) {
            inSampleSize *= 2;
        }
    }
    return inSampleSize;
}

2. 使用完畢後主動回收

// 使用圖片後
if (bitmap != null && !bitmap.isRecycled()) {
    bitmap.recycle();      // 釋放原生記憶體
    bitmap = null;         // 幫助 GC 回收 Java 物件
    System.gc();           // 建議執行垃圾回收(非強制)
}

3. 採用 LruCache 實作記憶體快取

private LruCache mMemoryCache;

@Override
protected void onCreate(Bundle savedInstanceState) {
    // 獲取最大可用記憶體的 1/8 作為快取
    final int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);
    final int cacheSize = maxMemory / 8;
    mMemoryCache = new LruCache(cacheSize) {
        @Override
        protected int sizeOf(String key, Bitmap bitmap) {
            return bitmap.getByteCount() / 1024; // KB 為單位
        }
    };
}

public void addBitmapToMemoryCache(String key, Bitmap bitmap) {
    if (getBitmapFromMemCache(key) == null) {
        mMemoryCache.put(key, bitmap);
    }
}

public Bitmap getBitmapFromMemCache(String key) {
    return mMemoryCache.get(key);
}

進階優化建議

  • 使用成熟圖片載入庫:Glide、Picasso、Coil 等庫已內建記憶體管理、縮放、快取機制,強烈建議生產環境直接使用。
  • 避免在主執行緒解碼大圖:使用 AsyncTask、ExecutorService 或協程在背景執行緒處理。
  • 設定 android:largeHeap:在 Manifest 中申請大記憶體(僅作為最後手段,可能導致系統整體記憶體緊張)。
  • 針對 Android 8.0+ 使用 Hardware Bitmap:減少應用記憶體佔用。

總結:OOM 錯誤的根本原因是大圖直接載入導致記憶體暴增。透過「縮放載入 + 及時回收 + 記憶體快取」三板斧,配合成熟圖片庫,即可徹底解決此類崩潰問題。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved