【问题标题】:Again - java.lang.OutOfMemoryError: bitmap size exceeds VM budget再次 - java.lang.OutOfMemoryError: 位图大小超出 VM 预算
【发布时间】:2012-01-07 08:04:12
【问题描述】:

我收到“java.lang.OutOfMemoryError:位图大小超过 VM 预算”错误...我正在做的是从服务器下载大约 50 个图像并将它们存储在内存中。

当我第一次看到这个问题时,我优化了我们的图像以仅下载缩略图(50 个 JPEGS,每个 ~12kB,大小 160x240 像素),并在我不需要它们时通过调用 Bitmap.recycle() 开始释放它们。一切都在较新的手机上运行,​​该过程可以获得 32MB,但在最大 16MB 的旧手机上不行。

所以我的问题是:

  • 在旧手机上所有进程限制为 32MB 或更少是否正确(即 Runtime.getRuntime().maxMemory() 调用返回的内存)并且此内存用于Dalvik、框架、应用程序和数据?

  • 我们能否在应用程序中使用比 Runtime.getRuntime().maxMemory() 返回的内存更多的内存?

  • 我应该如何优化图像 - 它们现在已经很小了...我应该开始将它们交换到内部闪存/SD 吗?只要它们显示在 GridView...

  • 中,我就会将它们保存在内存中

感谢您的帮助 - 我在这里完成了类似的线程并完成了我在那里看到的......但这仍然不够......


编辑更新

我在weakwire 回答之后添加了这些 cmets。

• 在我的例子中,我下载了大约 50 个图像并将它们全部存储在内存中的位图对象中。请看下面我为什么这样做。

Bitmap 对象中的图像占用多少内存?是否存在原始格式意味着如果图像是160x240x24bpp,它在内存中占用~115 kB,那么50 images are ~6MB正确吗?

• 我还读到图像不是我的进程堆的一部分,但它们被计算在内,因此使用 ma​​xMemory()、totalMemory()、freeMemory() 并没有真正的帮助。 正确吗?

• 我的应用程序 UI 具有完整的自定义图形(60 个 png 文件,其中许多是 draw9pacth 格式)

• 我在 24/32 MB 设备上没有问题,我只有在 16 MB 设备上遇到问题

• 当我下载所有 50 张图像并将它们存储到内存中时,我会以 2 列宽度 GridView 显示它们。我认为为此我需要将所有图像保留在堆上(保存到内部闪存我认为不是解决方案)。 这是正确的假设吗?

• 当我初始化应用程序并加载 UI 时,我可以看到在整个 16384kB 预算中分配了 5459kB 的 448kB 空闲内存。我假设我不能真正使用整个 16384kB + 如果我理解正确我无法从 maxMemory()、totalMemory()、freeMemory() 中真正看到已经加载的图像占用了多少,因为 dalvik-vm 没有“看到”这个堆。假设已经使用了 ~2M,我最多可以使用 ~14MB,我还剩下 5.5MB,所以我很容易在内存中有 50 张图像时遇到 OOM 问题……计算正确吗? p>

我一定会仔细阅读建议的视频 - 看起来不错 - 但weakwire,请尝试回答我的问题......谢谢你的时间!

【问题讨论】:

标签: android


【解决方案1】:

android:largeHeap="true" 是不可能的。如果没有正确完成,您将拥有一个非崩溃但缓慢的应用程序。

32MB 虚拟机很大。许多现代手机仍然使用 12MB 或 16MB。更大!= 更好。

你把图片放在哪里都没关系。唯一重要的是它们是否在 VM 中。

NO Runtime.getRuntime().maxMemory() 是您可以使用的最大内存。

位图是讨厌的对象(到目前为止,它是像素引用而不是位图对象本身)。如果没有正确释放,GC 将无法收集它们并且您会得到 OutOfMemoryError。

现在适合您的情况。 5MB 的图像不应导致 OOME。您有内存泄漏或另一个大型阻塞对象(可能是大型背景图像)。您应该检查 MAT 和 this video。有一些方法可以告诉垃圾收集器收集位图,但我认为你的问题可以很容易地避免。 5MB 的图像就可以了,并且可以管理。(您不需要一次显示全部 50 张吗?是吗?)

修改后的注释

我还读到图像不是我的进程堆的一部分,但它们被计算在内,因此使用 maxMemory()、totalMemory()、freeMemory() 并没有真正的帮助。对吗?

不。图像是堆的一部分,但未在 MAT 和其他工具中显示。我认为它们仅在 3.2 以上可见,但位图存在。

一旦我下载了所有 50 张图像并将它们存储到内存中,我就会在 2 列宽度的 GridView 中显示它们。我认为为此我需要将所有图像保留在堆上(保存到内部闪存我认为不是解决方案)。这是正确的假设吗?

不,这个假设是不正确的,这个假设是导致问题的原因。

为什么需要将它们全部放入堆中?您可以在存储设备(SD 或内部内存缓存)上使用带有 iamges 的无延迟 UI。如果您不确定如何在没有延迟加载的情况下处理图像,则必须延迟加载图像。您应该检查一些流行图像的代码(下)加载器,看看它们如何处理引用以及它们的缓存系统是如何组织的。您也可以使用其中之一

【讨论】:

  • 感谢 cmets,非常感谢。我花时间并在很大程度上更新了我的问题以使其更加具体。我可以请您再看一遍并尝试回答我的一些问题吗?非常感谢您的活动。
  • 延迟加载绝对是必要的——我必须弄清楚如何将它与我的自定义 GridView 适配器放在一起......谢谢
猜你喜欢
  • 2012-08-19
  • 2011-04-26
  • 1970-01-01
  • 2010-12-29
相关资源
最近更新 更多