web-dev-qa-db-ja.com

android-ビットマップ作成時のメモリ不足例外

2回目にビットマップを作成した後、次のエラーが発生します。

04-17 18:28:09.310: ERROR/AndroidRuntime(3458): Java.lang.OutOfMemoryError: bitmap size exceeds VM budget

this._profileBitmap = Bitmap.createBitmap(_profileBitmap, xCoor,  yCoor, width, height);

ログから:

04-17 18:27:57.500: INFO/CameraCropView(3458): Original Photo Size: W 1536 x H 2048   
04-17 18:28:06.170: INFO/CameraCropView(3458): xCoor: 291   
04-17 18:28:06.170: INFO/CameraCropView(3458): yCoor: 430    
04-17 18:28:06.170: INFO/CameraCropView(3458): Width: 952  
04-17 18:28:06.170: INFO/CameraCropView(3458): Height: 952  

画像が大きいのでエラーになります。しかし興味深いのは、最初にエラーが発生せず、2回目に写真を撮ったときにのみ発生することです。このため、このprofileBitmapは破棄されていません。これをどのようにクリーンアップしますか?

14
dropsOfJupiter

私は同じ問題を抱えており、このように修正しました:

私のアプリのサイズは〜18MBで、空きメモリがどれだけ残っているかを確認すると、654KB(1GB RAMで!)のショックを受けました。だから私はプロジェクトからほぼすべての画像を削除し、最初の起動時にインターネットからダウンロードし、必要に応じてSDカードからの写真を使用しました。

アプリの使用量の合計/空きメモリを確認するには:

 Runtime.getRuntime().totalMemory();
 Runtime.getRuntime().freeMemory();

編集:私は主なことを忘れました-あなたのマニフェストに、アプリケーションタグの間に次の行を追加してください:

Android:largeHeap="true"

15
Vitas

Androidのビットマップでのメモリ例外には多くの問題があり、その多くはstackoverflowで説明されています。既存の質問を調べて、既存の質問の1つと一致するかどうかを確認し、一致しない場合は、状況の違いを書いておくとよいでしょう。

いくつかの例:

ビットマップサイズが大きいためメモリ不足例外

Android:ギャラリーでのメモリ不足の例外

画像処理時のAndroidのメモリ不足例外の処理

など: https://stackoverflow.com/search?q=Android+out+of+memory+exception+bitmap

12
ThomasW

Androidビットマップ処理のヒント

Androidアプリケーションでメモリ不足の例外を回避できるヒントを次に示します。

  1. アプリケーションコンテキストではなく、常にアクティビティコンテキストを使用します。アプリケーションコンテキストはガベージコレクションできないためです。アクティビティが終了したらリソースを解放します。 (オブジェクトのライフサイクルはアクティビティのライフサイクルと同じである必要があります)。

2。アクティビティが終了したとき。 HEAP DUMP(Android studioのメモリ分析ツール))を確認します。

終了したアクティビティからのHEAP DUMPにオブジェクトがある場合、メモリリークが発生します。コードを確認し、メモリリークの原因を特定します。

  1. 常にinSampleSizeを使用

今inSampleSizeとは何ですか? inSampleSizeの助けを借りて、実際には、サブサンプル画像ではなく、メモリ内のすべてのピクセルを取得しないようにデコーダーに指示しています。これにより、元の画像よりも少ない数のピクセルがメモリに読み込まれます。元の画像から4ピクセルごとまたは2ピクセルごとにグラブするようにデコーダーに指示できます。 inSampleSizeが4の場合、デコーダは元の画像のピクセル数の1/16の画像を返します。

どれだけのメモリを節約できましたか?計算:)

  1. メモリにロードする前にビットマップディメンションを読み取ります。

    画像をメモリにロードする前にビットマップの寸法を読み取ることで、
    メモリエラー?学びましょう

    inJustBounds = trueを使用

ここに、メモリにロードする前に画像の次元を取得するためのテクニックがあります。

 BitmapFactory.Options options = new BitmapFactory.Options();
 options.inJustDecodeBounds = true;
 Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.id.myimage,    options);
 int imageHeight = options.outHeight;
 int imageWidth = options.outWidth;
 String imageType = options.outMimeType;

上記のコードスニペットでは、画像やビットマップは提供されません。ビットマップオブジェクトの場合はnullを返します。しかし、それは間違いなくその画像の幅と高さを返します。これはR.id.myimageです。

これで、画像の幅と高さが決まりました。次の要因に基づいて画像を拡大または縮小できます。

  • 画像の表示に使用されるImageViewサイズ。
  • 使用可能なメモリ容量。 ActivityManagerおよびgetMemoryClassを使用して、使用可能なメモリ量を確認できます。
  • デバイスの画面サイズと密度。

    1. 適切なビットマップ構成を使用する

    ビットマップ構成は、画像の色空間/色深度です。 Androidのデフォルトのビットマップ構成はRGB_8888で、ピクセルあたり4バイトです。

ピクセルあたり2バイトを使用するRGB_565カラーチャネルを使用する場合。同じ解像度のメモリ割り当ての半分:)

  1. リサイクルの目的でinBitmapプロパティを使用します。

  2. 静的なDrawable Objectはガベージコレクションできないため作成しないでください。

  3. マニフェストファイルで大きなヒープを要求します。

  4. 多くの画像処理(メモリを大量に消費するタスク)を実行している場合は複数のプロセスを使用するか、NDK(c、c ++を使用したネイティブ開発)を使用する

6
Hammad Tariq

これは、ビットマップを直接ロードしているために発生し、多くのメモリを消費します。代わりに、_profileBitmapの画像の縮小版を使用してください。この男はそれをかなりよく説明しています。 http://androidcocktail.blogspot.in/2012/05/solving-bitmap-size-exceeds-vm-budget.html

4
android

使い終わったら、ビットマップでrecycle()を呼び出してみてください。これにより、すべての画像データが消去され、メモリが解放されます。この後でビットマップを描画しようとすると、アプリがクラッシュします。クラッシュが発生した場合は、ビットマップ上にまだ何が残っているかを見つけるのに役立つことがあります。

2
skorulis

ベクトルDrawableを使用できます。 xmlファイルを使用して画像を記述するため、消費メモリが少なくなります。そのためには、画像にSVG形式を使用し、次の2つのソリューションのいずれかを使用してxmlファイルを生成する必要があります。

  • 解決策1:Android Studioでベクターアセットスタジオを使用する:プロジェクトのDrawableファイルを右クリック->新規->ベクターアセット
  • 解決策2:svg2Android Webサイトを使用する: https://inloop.github.io/svg2Android

詳細については、このリンクを確認してください。
https://developer.Android.com/studio/write/vector-asset-studio.html

この問題が発生したのは、ビットマップを1回変更してから、変更されたバージョンをもう一度変更したため、同じビットマップの3つのバージョン(元のバージョンと2つの変更されたバージョン)が同時にメモリに存在するためです。

画像編集コードを変更して両方の変更を同じビットマップに一種のバッチプロセスとして適用し、アプリがメモリに保持する必要のある変更されたバージョンの数を半分にして修正しました。

1
Andrew Koster

大きな画像では、それらを小さなサイズにサンプリングすることで回避できます。以下の例を使用-

    File f = new File(selectedImagePath); 

    // First decode with inJustDecodeBounds=true to check dimensions
    final BitmapFactory.Options options = new BitmapFactory.Options();
    options.inJustDecodeBounds = true;
    BitmapFactory.decodeStream(new FileInputStream(f), null, options); 
    // Calculate inSampleSize
    options.inSampleSize = calculateInSampleSize(options, 720, 1280); //My device pixel resolution
    // Decode bitmap with inSampleSize set
    options.inJustDecodeBounds = false;    
    Bitmap bmpPic = BitmapFactory.decodeStream(new FileInputStream(f), null, options); 


    Bitmap bmpPic1 = Bitmap.createBitmap(bmpPic, 0, 0, bmpPic.getWidth(), bmpPic.getHeight(), mat, true);   
    img.setImageBitmap(bmpPic1);  //img is your ImageView

リファレンス- http://developer.Android.com/training/displaying-bitmaps/load-bitmap.html

1
amir ansari

電話の電源をオフにしてから再度オンにしたときにも同じ問題が発生しました。ビットマップをnullに設定してSystem.gc()を呼び出すだけです。すべての問題を修正しました。

0
a54studio