web-dev-qa-db-ja.com

OutofMemoryError:ビットマップサイズがVM予算(Android)を超えています

BitmapFactoryで例外を取得します。何が問題なのかわからない。 (問題は推測できますが、なぜ発生するのかわかりません)

ERROR/AndroidRuntime(7906):Java.lang.OutOfMemoryError:ビットマップサイズがVM予算
 
 ERROR/AndroidRuntime(7906):Android.graphics.BitmapFactoryを超えています.decodeFile(BitmapFactory.Java:295)

私のコードは非常に単純です。デフォルトの画像を使用してXMLレイアウトを定義しました。 SDカードにbmをロードしようとしています(存在する場合はそうです)。そうでない場合は、デフォルトの画像が表示されます。とにかく..ここにコードがあります:

public class showpicture extends Activity {
  public void onCreate(Bundle savedInstanceState) {

         /** Remove menu/status bar **/
         requestWindowFeature(Window.FEATURE_NO_TITLE);
         final Window win = getWindow();   
         win.setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,WindowManager.LayoutParams.FLAG_FULLSCREEN);

            Bitmap bm;
         super.onCreate(savedInstanceState);
         setContentView(R.layout.showpicture);
            try {
         ImageView mImageButton = (ImageView)findViewById(R.id.displayPicture);
         bm = Bitmap.createScaledBitmap(BitmapFactory.decodeFile("/sdcard/dcim/Camera/20091018203339743.jpg"),100, 100, true);
         parkImageButton.setImageBitmap(bm);
         }
         catch (IllegalArgumentException ex) {
          Log.d("MYAPP",ex.getMessage());
         } 
            catch (IllegalStateException ex) {

bm=Bitmap.createScaledBitmapで失敗しますか?私はフォーラムでいくつかの調査をしました、そしてそれは指摘しました この投稿 私はそれがなぜ機能しないのか分かりません。どんな助けでも素晴らしいでしょう!ありがとう、

クリス。

22
Chrispix
4
Steven Shih

inSampleSizeは良いヒントです。ただし、ファイルの大きなビットマップは通常ユーザーファイルであり、小さなサムネイルからデジカメの12MP画像までさまざまであるため、固定値はうまく機能しないことがよくあります。

これが素早く汚いロードルーチンです。より良いコード化されたループ、より高速なデコードのために2の累乗を使用するなど、改善の余地があることを私は知っています。しかし、それは実用的なスタートです...

public static Bitmap loadResizedBitmap( String filename, int width, int height, boolean exact ) {
    Bitmap bitmap = null;
    BitmapFactory.Options options = new BitmapFactory.Options();
    options.inJustDecodeBounds = true;
    BitmapFactory.decodeFile( filename, options );
    if ( options.outHeight > 0 && options.outWidth > 0 ) {
        options.inJustDecodeBounds = false;
        options.inSampleSize = 2;
        while (    options.outWidth  / options.inSampleSize > width
                && options.outHeight / options.inSampleSize > height ) {
            options.inSampleSize++;
        }
        options.inSampleSize--;

        bitmap = BitmapFactory.decodeFile( filename, options );
        if ( bitmap != null && exact ) {
            bitmap = Bitmap.createScaledBitmap( bitmap, width, height, false );
        }
    }
    return bitmap;
}

ところで、新しいAPIには、画像を画面のDPIに合わせるためのBitmapFactory.Optionもたくさんありますが、それらが本当に何かを単純化するかどうかはわかりません。 Android.util.DisplayMetrics.densityを使用するか、メモリ消費量を減らすために単に固定サイズを使用すると、より効果的に機能するようです。

13
M. Schenk

これを参照して linkoutOfMemoryエラーは次の方法で解決できることに注意してください。

public Bitmap decodeFile(String filePath) {

Bitmap bitmap = null;
BitmapFactory.Options options = new BitmapFactory.Options(); 
options.inPurgeable = true;

try {
BitmapFactory.Options.class.getField("inNativeAlloc").setBoolean(options,true);

} catch (IllegalArgumentException e) {
    e.printStackTrace();
} catch (SecurityException e) {
    e.printStackTrace();
} catch (IllegalAccessException e) {
    e.printStackTrace();
} catch (NoSuchFieldException e) {
    e.printStackTrace();
}

if(filePath != null)
{
    bitmap = BitmapFactory.decodeFile(filePath, options);               
}

return bitmap;
}
5
SampsonTan

ビットマップの作成をメモリ不足エラーから保護するようにしてください!ほとんどのプラットフォームでは、Androidで遊ぶメモリが少なく、ビットマップですぐに使い果たされます。また、ビットマップをできるだけ手動でリサイクルするようにしてください。ガベージコレクションはかなり遅くなる可能性があります。

try{            
  Bitmap myFragileBitmap = Bitmap.createBitmap(500, 500, Bitmap.Config.ARGB_8888);
}
catch(IllegalArgumentException e){
  Log.e(TAG,"Illegal argument exception.");
}
catch(OutOfMemoryError e){
  Log.e(TAG,"Out of memory error :(");
}
4
Ralphleon

問題を解決したと思われる次のコードを使用して、ビットマップのサイズを変更することになりました。

BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 8;
Bitmap preview_bitmap = BitmapFactory.decodeFile(mPathName, options);
4
Chrispix

私はそれがそうだと思います-それが言うことです。画像が大きすぎて、メモリが使い果たされるとストリームに読み込まれるため、例外がスローされます。全体的にどれだけのメモリがあるかではなく、特定のアクティビティがどれだけ利用できるかという問題です。

1
Bostone

decodefileでこれらのオプションを使用します。ビットマップがVMバジェットの問題を超えていることを確認できれば幸いです。

BitmapFactory.Options bfOptions=new BitmapFactory.Options(); 

bfOptions.inDither=false;          //Disable Dithering mode
bfOptions.inPurgeable=true;       //Tell to gc that whether it needs free memory, the Bitmap can be cleared
bfOptions.inInputShareable=true;  //Which kind of reference will be used to recover the Bitmap data after being clear, when it will be used in the future
bfOptions.inTempStorage=new byte[32 * 1024]; 
1
Sando

DDMSを確認しましたか? Androidは大きな画像をかなりうまく処理しているように見えるので、私が遭遇したことでは、おそらく画像のサイズではありません。DDMSでヒープをトレースすると、たまたまたくさんの空きメモリこれを追加することでヒープを「拡張」できます

static { @SuppressWarnings("unused")
byte dummy[] = new byte[ 8*1024*1024 ]; }    

コードに、ヒープを強制的に拡張します。それはそれを少し少なくするかもしれません。残念ながら、例外を除いて、ある程度のバイト数を割り当てることができないと主張しています。 1Mと言います。 「フリー」ラインを見ると、最大のブロックが>> 1Mであることがわかります。そこには私には理解できない奇妙なことがあります。画像のスワイプ速度にも関係ありません。いくつかのスレッドで、ビットマップに対して「リサイクル」などと呼ぶことができることを知りました。ヒープサイズが取得したサイズをはるかに上回っている場合に、なぜそれが役立つのかはまだわかりません。

0
Meymann

画像のサイズを320x240から64x240(ダウンスケール)に変更し始めてからプロジェクトにインポートすると、このエラーが発生しました(レンダリング速度を向上させたいと思っていたため、この時点までは役に立たないアルファ領域がたくさん含まれていました)。

今、最後の答えは非常に理にかなっています:

この静的な{@SuppressWarnings( "unused")バイトダミー[] =新しいバイト[8 * 1024 * 1024];を追加することで、ヒープを「拡張」できます。 }をコードに追加して、ヒープを強制的に拡張します。それはそれを少し少なくするかもしれません。

これが私に起こったことだと思います。 Androidは自動的にドローアブルをビットマップにデコードします(そして、コンパイル時にすべてヒープに保存されますか?)

実行時に小さいバージョンの画像を使用すると、エラーが発生し始めました(BitmapFactory.decodeResourceとBitmap.createScaledBitmapを使用してレトロなグラフィックでVGAゲームをプログラムしているため、実行時に拡大します)。

marveが言ったように、私の場合、ドローアブル/イメージを縮小してプロジェクトにインポートした後、ヒープが十分に大きくありません。

画像のサイズをより大きなサイズ(320x240)に戻すと、OutOfMemoryExceptionを取り除くことができました。これにより、問題が確認されますか?

0
calav3ra