Android:BitmapFactory.decodeStream()内存不足,带有2MB空闲堆的400KB文件

May*_*ank 65 heap android

我的应用程序在源代码中的以下行遇到OOM错误:

image = BitmapFactory.decodeStream(assetManager.open(imgFilename));
Run Code Online (Sandbox Code Playgroud)

就在分配之前导致应用程序被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
Run Code Online (Sandbox Code Playgroud)

DDMS报告了关于堆状态的类似图片:

Heap Size:  5.254 MB
Allocated:  2.647 MB
Free:   2.607 MB
%Used:  50.38%
#Objects    49,028  
Run Code Online (Sandbox Code Playgroud)

单步执行此行会导致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
Run Code Online (Sandbox Code Playgroud)
  1. 在Windows上,"imgFileName"引用的文件大小报告为<400K.那么为什么BitmapFactory.decodeStream尝试分配2MB呢?
  2. 当似乎有足够的可用空间时,为什么会出现OOM错误?

此应用针对Android 2.2及更高版本.

提前致谢!

Pau*_*que 87

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);
Run Code Online (Sandbox Code Playgroud)

参考: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);
Run Code Online (Sandbox Code Playgroud)

参考: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);
Run Code Online (Sandbox Code Playgroud)

您可以根据设备的屏幕大小自定义inSampleSize.要获得屏幕尺寸,您可以:

DisplayMetrics metrics = new DisplayMetrics();
((Activity) activity).getWindowManager().getDefaultDisplay().getMetrics(metrics);
int screenWidth = metrics.widthPixels;
int screenHeight =metrics.heightPixels;
Run Code Online (Sandbox Code Playgroud)

其他教程: - http://developer.android.com/training/displaying-bitmaps/load-bitmap.html - http://developer.android.com/training/displaying-bitmaps/index.html


Mic*_*Bak 42

有关更有效地加载大型位图的指南,请参阅此内容:

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

一个400 KB的图像文件可以轻松占用5-10 MB的RAM.

  • 我仍然有一个OutOfMemoryError与这个谷歌推荐...沮丧. (27认同)

nEx*_*are 8

磁盘上文件的大小不一定与内存中文件的大小一致.文件可能会被压缩,解码时不会被压缩.您需要在计算中考虑到这一点.

将图像的大小(宽度x高度)乘以图像的颜色深度,以获得图像的内存大小.