【问题标题】:bitmap size exceeds VM budget Error on Android位图大小超出虚拟机预算 Android 上的错误
【发布时间】:2011-10-29 19:21:10
【问题描述】:

我正在将 100 张图片从 Asset 文件夹加载到一个数组对象中。图片非常小(每个 png ~20k),我使用此代码对其进行处理,以防止内存泄漏和优化性能:

在循环中:

// create resized bitmap from asset resource
        InputStream istr = assetManager.open(pics[i]);
        Bitmap b = BitmapFactory.decodeStream(istr);
        b = Bitmap.createScaledBitmap(b, 240, 240, true);

其中 pics[i] 是位于我的资产文件夹中的文件名列表。

代码对我有用,但我仍然不时收到来自用户的错误(我在开发者控制台错误中看到它):

java.lang.OutOfMemoryError: bitmap size exceeds VM budget
at android.graphics.Bitmap.nativeCreate(Native Method)
at android.graphics.Bitmap.createBitmap(Bitmap.java:468)
at android.graphics.Bitmap.createBitmap(Bitmap.java:435)
at android.graphics.Bitmap.createScaledBitmap(Bitmap.java:340)

有什么可以改进的吗?或者这是 Android 的世界,我们永远无法交付完美的应用程序?

【问题讨论】:

标签: android image memory memory-leaks


【解决方案1】:

当然你可以改进一些东西:不要同时将太多图片加载到内存中(或减小它们的大小)。有些设备没有太多可用内存。您的设备可能比您的某些客户手机具有更高的堆限制。因此,当它为您工作时,它会为它们崩溃(请参阅this video 了解一些堆限制 [at 4:44])。

您可以通过ActivityManager.getMemoryClass() 获取可用堆大小。

要改善这一点,请测试您现在需要哪些图片(显示哪些图片),哪些不是。仅加载所需的位图并回收不再需要的位图。

也可以尝试使用BitmapFactory.decodeResource()BitmapFactory.Options.inSampleSize。这使您可以直接以较低的分辨率加载图像,而无需以完整尺寸加载它们,然后像​​您在此处所做的那样调整它们的大小。

【讨论】:

  • BitmapFactory.decodeResource() 用于从 Res 加载图像,不是吗?我从资产加载它们
  • 感谢您的评论,我已经重写了代码。我仅在显示图像时才加载图像。 android中的这个内存泄漏问题让我写了糟糕的代码..
  • 嘿,是的,decodeResource() 是用于可绘制资源的。抱歉,没有完全意识到您在这里使用资产。不过还有一个decodeStream(InputStream is, Rect outPadding, BitmapFactory.Options opts)函数,不知道对你有没有用,我自己没用过。
  • 是的,这就是我的解决方案!我使用了 hotveryspicy 的链接建议,它建议使用 options.inSampleSize,从那时起就没有内存泄漏错误..
【解决方案2】:

位图未压缩,因此它们存储在width * height * 4 字节中。这意味着每个图像使用大约 225 KB 的内存。 100 张图像需要大约 22 MB 的内存。最小堆大小为 16 MB,但设备通常具有 24+ MB 堆。而这个堆不仅用于数据,还用于活动、视图等。这意味着您无法加载 100 个这种大小的位图。

【讨论】:

  • 谢谢。我有一种感觉,我在这里做错了什么:)
【解决方案3】:

根据经验,您应该只需要显示用户实际可以看到的内容。在内存中保存其他任何东西(图形)只是锦上添花。这就是为什么具有更高分辨率屏幕的设备将有更大的可用堆大小。

例如,在 320x480 的屏幕上,您至少需要 320x480x4=614400 (600kb)。

考虑到这个概念,您需要考虑是否需要在内存中保存 100 个Bitmaps。用户是否一次查看 100 个Bitmaps?在这种情况下,您可以在不降低用户体验的情况下降低图像质量(屏幕上只有这么多像素)。用户是否滚动了 100 个Bitmaps?然后根据需要动态转储和加载图像(为了平滑而进行一些缓存)。

总有一种解决方法。

【讨论】:

  • 即使我只在用户看到图像时才加载图像,它也会抛出该异常。 Android中加载图片时存在一些内存泄漏
  • 这就是我编写代码的原因(基于我在某处看到的一些示例): InputStream istr = assetManager.open(pics[i]);位图 b = BitmapFactory.decodeStream(istr); b = Bitmap.createScaledBitmap(b, 240, 240, true);
猜你喜欢
  • 1970-01-01
  • 2012-08-09
  • 2012-05-31
  • 1970-01-01
  • 1970-01-01
  • 2012-08-19
  • 2011-07-19
  • 1970-01-01
  • 2010-12-07
相关资源
最近更新 更多