Android:OutofMemoryError:位图大小超过VM预算,没有理由我可以看到

时间:2010-06-14 12:02:51

标签: android gallery imageview out-of-memory ddms

我有一个超过600x800像素的图库的OutOfMemory异常。


环境

我一直在使用带有大约600x800像素的JPG图像的图库。

由于我的内容可能比图像更复杂,我已将每个视图设置为包含带有JPG的ImageView的RelativeLayout。

为了“加速”用户体验,我有一个4个插槽的简单缓存,它预取(在一个looper中)左边大约1个图像,1个图像右边显示图像并将它们保存在4槽HashMap中。

平台

我正在使用256 RAM和128堆大小的AVD,屏幕为600x800。 它也发生在Entourage Edge目标上,除了使用设备它更难调试。


问题

我一直有例外:

OutofMemoryError: bitmap size exceeds VM budget

在获取第五张图像时会发生这种情况。我试图改变图像缓存的大小,它仍然是相同的。


奇怪的是:应该没有内存问题

为了确保堆限制与我需要的距离非常远,我在开始时定义了一个虚拟的8MB数组,并将其保留为未引用,以便立即调度。它是活动线程的成员,定义如下

static { @SuppressWarnings("unused")
byte dummy[] = new byte[ 8*1024*1024 ]; }    

结果是堆大小接近11MB并且它们都是免费的。 注意我在它开始崩溃后添加了这个技巧。它使OutOfMemory不那么频繁。

现在,我正在使用DDMS。在崩溃之前(崩溃后变化不大),DDMS显示:

ID  Heap Size   Allocated   Free       %Used    #Objects
1   11.195 MB   2.428 MB    8.767 MB   21.69%   47,156  

在细节表中显示:

Type  Count  Total Size   Smallest   Largest   Median    Average
free  1,536  8.739MB      16B        7.750MB   24B       5.825KB

最大的块是7.7MB。然而LogCat说:

ERROR/dalvikvm-heap(1923): 925200-byte external allocation too large for this process.

如果你关注中位数和平均值之间的关系,可以假设大多数可用的块非常小。但是,有一个块足够大的位图,它是7.7M。怎么还不够呢?

注意:我记录了一个堆跟踪。在查看分配的数据量时,感觉不会超过2M。它与DDMS的可用内存报告匹配。


  • 可能是我遇到像堆碎片一样的问题吗?
  • 如何解决/解决问题?
  • 堆是否共享给所有线程?
  • 可能是我以错误的方式解释DDMS读数,并且实际上没有900K块可以分配吗?如果是的话,有人可以告诉我在哪里可以看到吗?

非常感谢

Meymann

5 个答案:

答案 0 :(得分:12)

我认为你的情况并不特别。内存不足。内存中不能有多个600x800位图,它们会消耗太多内存。您应该将它们保存到SD并按需加载到内存。我认为这正是你所做的。

您应该注意的一件事:DDMS显示Java堆内存消耗。但是,DDMS中也没有显示本机内存。据我所知,位图是在本机内存中创建的。所以DDMS只是一个跟踪这些内存问题的糟糕工具。你只需要确保释放你的记忆,垃圾收集器不再需要它们时会收集这些图像。

垃圾收集器按照自己的计划工作。这就是你应该在你不再需要的位图上调用Bitmap.recycle()方法的原因。此方法可以释放您用完的本机内存。这样你就不依赖于GC了,你可以尽快释放最大的内存。

首先,您应该确保不泄漏位图。

这是关于内存分配的一个很好的post,它可以帮助你深入挖掘

答案 1 :(得分:5)

不确定它是否适合您,但您是否尝试过对图像进行超级采样Strange out of memory issue while loading an image to a Bitmap object

答案 2 :(得分:0)

我也在几周前面临类似的问题,我通过缩小图像达到最佳点来解决它。我已经在我的博客here中编写了完整的方法,并使用OOM倾向代码和OOM证明代码here上传了完整的示例项目。

答案 3 :(得分:0)

自从我提出这个问题以来已经有很多时间了。

答案应分为两部分: 前姜饼:你只是使用小图片,使用二次取样,也许一张屏幕大小的照片,并希望好。尝试确保在获取位图之前不要分配您无法释放的小项目。在生姜之前,bmps的记忆必须是连续的,并且它不计入VM内存中。总是看一下logcat。请参阅Google IO 2011中有关内存的讲座。 发布姜更容易。从Honeycomb开始,你的java区域甚至会计算位图。没有jni区域。 始终将回收用于您不需要的位图。不要等待GC。

答案 4 :(得分:0)

问题在2010年被问到,当时Froyo很新鲜。从那以后发生了很多事情。 在3.0之前,在JNI中分配了位图。记忆没有显示在Dalvik统计数据中。它不再是单片的。 在2.3之前,JNI的内存统计信息在logcat中不可用(位图解码调用JNI)。 4.4撤离更多空间。 5.0艺术大爆炸。 早在2010年,Nexus One就是高端产品,不到300MB。应用程序的预算约为16MB。现在几天,大约有8倍的记忆。