68

私のアプリは、ソースの次の行でOOMエラーが発生しています。

image = BitmapFactory.decodeStream(assetManager.open(imgFilename));

OOMエラーでアプリが強制終了される原因となる割り当ての直前:

(...)
08-05 21:22:12.443: I/dalvikvm-heap(2319): Clamp target GC heap from 25.056MB to 24.000MB
08-05 21:22:12.443: D/dalvikvm(2319): GC_FOR_MALLOC freed <1K, 50% free 2709K/5379K, external 18296K/19336K, paused 58ms
08-05 21:22:14.513: D/dalvikvm(2319): GC_EXTERNAL_ALLOC freed <1K, 50% free 2709K/5379K, external 18296K/19336K, paused 101ms
08-05 21:22:14.903: I/dalvikvm-heap(2319): Clamp target GC heap from 25.073MB to 24.000MB
08-05 21:22:14.903: D/dalvikvm(2319): GC_FOR_MALLOC freed 0K, 50% free 2709K/5379K, external 18312K/19336K, paused 53ms
08-05 21:22:22.843: D/ddm-heap(2319): Heap GC request
08-05 21:22:22.963: I/dalvikvm-heap(2319): Clamp target GC heap from 25.073MB to 24.000MB
08-05 21:22:22.963: D/dalvikvm(2319): threadid=1: still suspended after undo (sc=1 dc=1)
08-05 21:22:22.963: D/dalvikvm(2319): GC_EXPLICIT freed 1K, 50% free 2710K/5379K, external 18312K/19336K, paused 116ms

DDMSは、ヒープの状態について同様の図を報告します。

Heap Size:  5.254 MB
Allocated:  2.647 MB
Free:   2.607 MB
%Used:  50.38%
#Objects    49,028  

この行を1回ステップオーバーすると、OOMエラーが発生します。

08-05 21:26:04.783: D/dalvikvm(2319): GC_EXTERNAL_ALLOC freed <1K, 50% free 2710K/5379K, external 18312K/19336K, paused 57ms
08-05 21:26:05.023: E/dalvikvm-heap(2319): 2097152-byte external allocation too large for this process.
08-05 21:26:05.163: I/dalvikvm-heap(2319): Clamp target GC heap from 25.073MB to 24.000MB
08-05 21:26:05.163: E/GraphicsJNI(2319): VM won't let us allocate 2097152 bytes
08-05 21:26:05.163: D/dalvikvm(2319): GC_FOR_MALLOC freed 0K, 50% free 2710K/5379K, external 18312K/19336K, paused 30ms
08-05 21:26:05.283: D/skia(2319): --- decoder->decode returned false
  1. 「imgFileName」によって参照されるファイルのサイズは、Windowsでは<400Kであると報告されています。では、なぜBitmapFactory.decodeStreamが2MBを割り当てようとするのでしょうか。
  2. 十分な空き容量があるように見えるのに、なぜOOMエラーが発生するのですか?

このアプリはAndroid2.2以降を対象としています。

前もって感謝します!

4

8 に答える 8

91

Androidライブラリは画像の読み込みにそれほどスマートではないため、このための回避策を作成する必要があります。

私のテストでDrawable.createFromStreamは、より多くのメモリを使用しますBitmapFactory.decodeStream

配色を変更してメモリ(RGB_565)を減らすことができますが、画像の品質も低下します。

BitmapFactory.Options options = new BitmapFactory.Options();
options.inPreferredConfig = Config.RGB_565;
Bitmap bitmap = BitmapFactory.decodeStream(stream, null, options);

参照:http ://developer.android.com/reference/android/graphics/Bitmap.Config.html

拡大縮小された画像をロードすることもできます。これにより、メモリ使用量が大幅に削減されますが、画像の品質が低下しすぎないように、画像を知っておく必要があります。

BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 2;
Bitmap bitmap = BitmapFactory.decodeStream(stream, null, options);

参照:http ://developer.android.com/reference/android/graphics/BitmapFactory.Options.html

inSampleSizeを動的に定義するには、決定を下すために画像サイズを知りたい場合があります。

BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
bitmap = BitmapFactory.decodeStream(stream, null, options);
int imageHeight = options.outHeight;
int imageWidth = options.outWidth;

options.inJustDecodeBounds = false;
// recreate the stream
// make some calculation to define inSampleSize
options.inSampleSize = ?;
Bitmap bitmap = BitmapFactory.decodeStream(stream, null, options);

デバイスの画面サイズに応じて、inSampleSizeをカスタマイズできます。画面サイズを取得するには、次の操作を実行できます。

DisplayMetrics metrics = new DisplayMetrics();
((Activity) activity).getWindowManager().getDefaultDisplay().getMetrics(metrics);
int screenWidth = metrics.widthPixels;
int screenHeight =metrics.heightPixels;

その他のチュートリアル:-http: //developer.android.com/training/displaying-bitmaps/load-bitmap.html-http : //developer.android.com/training/displaying-bitmaps/index.html

于 2013-05-13T18:13:22.873 に答える
42

大きなビットマップをより効率的にロードするためのガイドについては、これを参照してください。

http://developer.android.com/training/displaying-bitmaps/load-bitmap.html

400 KBのイメージファイルは、5〜10MBのRAMを簡単に使用できます。

于 2012-08-05T21:47:59.377 に答える
8

ディスク上のファイルのサイズは、メモリ内のファイルのサイズと必ずしも一致しません。ファイルが圧縮されている可能性がありますが、デコードされた場合は圧縮されません。あなたはあなたの計算でそれを説明する必要があります。

画像のサイズ(幅x高さ)に画像の色深度を掛けて、画像のメモリ内サイズを取得します。

于 2012-08-05T21:46:46.250 に答える
3

基本的に、スケーリングを試みることで問題を解決でき、Bitmapメモリ消費量が削減されます。これを行うには、ここに示されているメソッドをコピーできます。

また、Android Developeresには、大きなビットマップを読み込む方法をよりよく理解するのに役立つ専用のページがあります。公式ドキュメントをご覧ください。

于 2012-08-05T22:52:26.800 に答える
1

上記の答えは明らかに正しいですが、ImageViewのbitmap / srcプロパティが使用されなくなったとき、主にアクティビティが破棄されたときに、明示的にnullに設定することもお勧めします。その他の強力なリソース(大きなテキスト、オーディオ、ビデオ)なども無効になる場合があります。これにより、リソースが即座に解放され、GCが収集するのを待つ必要がなくなります。

于 2014-01-04T12:13:47.047 に答える
0

グライドライブラリを介してビットマップの割り当てを試みることができます。Glideは、最も適切な方法(デバイスと環境に固有)を使用して、ビットマップファイルをグラフィカルレイヤー(ImageView)に移植します。

素晴らしくて簡単:

Glide.with(getContext())
            .load(imageFile.getPath())
            .into(previewImageView);
于 2020-04-21T21:10:45.077 に答える
-2

以下のメソッドを使用してOutOfMemoryErrorの問題を解決しました

private Bitmap downloadImageBitmap(String sUrl) {
        this.url = sUrl;
        bitmap = null;
                    try {
            BitmapFactory.Options options = new BitmapFactory.Options();
            for (options.inSampleSize = 1; options.inSampleSize <= 32; options.inSampleSize++) {
                InputStream inputStream = new URL(sUrl).openStream();  
                try {
                    bitmap = BitmapFactory.decodeStream(inputStream, null, options);      
                    inputStream.close();
                    break;
                } catch (OutOfMemoryError outOfMemoryError) {
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        return bitmap;
    }
于 2018-07-09T06:56:02.020 に答える
-3

サンプルサイズを2変更します。問題は解決しました。ただし、画質が損なわれないように注意してください。

于 2015-09-23T10:05:22.570 に答える