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

我的应用程序在源代码中的以下行中遇到了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 
  1. Windows上报告“imgFileName”引用的文件大小<400K。 那么为什么BitmapFactory.decodeStream尝试分配2MB?
  2. 为什么看起来有足够的可用空间时会出现OOM错误?

这个应用程序的目标是Android 2.2及以上。

提前致谢!

Android库对于加载图片来说不是那么聪明,所以你必须为此创build解决方法。

在我的testing中, Drawable.createFromStreamBitmapFactory.decodeStream使用更多的内存。

您可以更改颜色scheme来减less内存(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

您也可以加载缩放的图像,这将减less很多的内存使用,但你必须知道你的图像不会失去太多的质量。

 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

要dynamic定义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.htmlhttp://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高)乘以图像的颜色深度,以获得图像的内存大小。

基本上你可以通过试图缩放你的Bitmap来解决你的问题,你会看到内存消耗减less。 要做到这一点,你可以复制他在这里显示的方法。

此外,Android Developeres上还有一个专门的页面,可以帮助您更好地了解如何加载大型位图。 看看官方文档 。

虽然上面的答案显然是正确的,但更好的做法是将ImageView的bitmap / src属性显式设置为null ,当它们不再使用时,主要是在您的活动被销毁时。 任何其他重要资源(大文本,audio,video)等也可能被取消。 这确保资源被即时释放,而不是等待GC收集。

我更改insample大小2.我的问题已解决。 但要确保图像的质量不会被破坏。