我的Android App在执行下面代码时出现了OutOfMemoryError异常
image = BitmapFactory.decodeStream(assetManager.open(imgFilename));
App执行到这一步就会出现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可以看到当时内存堆的使用情况
只要指定到这一行就会出现OutOfMemoryError异常
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
在windows中可以看到图片文件的大小是小于400K的,而BitmapFactory.decodeStream()方法却要试图分配2M的内存。
出现这个异常是因为Android类库在处理图片载入时不是很智能,我们还需要做一些额外的工作。
我测试发现,Drawable.createFromStream方法要比BitmapFactory.decodeStream方法占用更多的内存。
你可以通过修改图片的颜色模式(Color schema)来减少创建图片使用的内存量
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);
你可以根据用户手机屏幕的大小来计算图片的尺寸,如下代码可以获得手机设备的尺寸。
DisplayMetrics metrics = new DisplayMetrics();
((Activity) activity).getWindowManager().getDefaultDisplay().getMetrics(metrics);
int screenWidth = metrics.widthPixels;
int screenHeight =metrics.heightPixels;