我有一个超过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的可用内存报告匹配。
非常感谢
Meymann
答案 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)
答案 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倍的记忆。