私のアプリは、ソースの次の行で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
この行をシングルステップ実行すると、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
このアプリは、Android 2.2以降を対象としています。
前もって感謝します!
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
大きなビットマップをより効率的にロードするためのガイドについては、これを参照してください。
http://developer.Android.com/training/displaying-bitmaps/load-bitmap.html
400 KBの画像ファイルは、5〜10 MBのRAMを簡単に占有できます。
ディスク上のファイルのサイズは、メモリ内のファイルのサイズと必ずしも一致しません。ファイルが圧縮されている可能性がありますが、デコード時には圧縮されません。計算でそれを考慮する必要があります。
画像のサイズ(幅x高さ)に画像の色深度を掛けて、画像のメモリ内サイズを取得します。
上記の答えは明らかに正しいですが、より良い方法は、explicitly ImageViewのビットマップ/ srcプロパティをnullに設定することです。アクティビティが破壊されています。その他のヘビーデューティーリソース(大きなテキスト、オーディオ、ビデオ)なども無効になる場合があります。これにより、GCが収集されるのを待たずに、リソースが即座に解放されます。
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;
}