我的库超过 600x800 像素 JPEG 时出现 OutOfMemory 异常。
环境
我一直在使用包含 600x800 像素左右的 JPG 图片的图库。
由于我的内容可能比图像更复杂一些,因此我将每个 View 设置为将 ImageView 与 JPG 包装在一起的 RelativeLayout。
为了“加速”用户体验,我有一个简单的 4 个插槽缓存,预取(在循环器中)大约 1 个图像左侧和 1 个图像右侧显示图像,并将它们保存在 4 个插槽 HashMap 中。
平台
我正在使用 256 RAM 和 128 堆大小的 AVD,屏幕为 600x800。 它也发生在 Entourage Edge 目标上,只是在设备上更难调试。
问题
我遇到了一个异常:
OutofMemoryError: bitmap size exceeds VM budget
在获取第五张图片时会发生这种情况。我已尝试更改图像缓存的大小,但还是一样。
奇怪的是:应该没有内存问题
为了确保堆限制离我需要的很远,我在开始时定义了一个 8MB 的虚拟数组,并没有对其进行引用,因此它会立即被调度。它是 Activity 线程的成员,定义如下
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
最大的 block 是 7.7MB。然而 LogCat 说:
ERROR/dalvikvm-heap(1923): 925200-byte external allocation too large for this process.
如果您介意中位数和平均值的关系,可以假设大多数可用 block 非常小。但是,有一个足够大的 block 用于位图,它是 7.7M。怎么还不够呢?
注意:我记录了一个堆跟踪。看分配的数据量,感觉分配不超过2M。它确实与 DDMS 的可用内存报告相符。
- 会不会是我遇到了诸如堆 fragment 之类的问题?
- 如何解决/解决问题?
- 堆是否共享给所有线程?
- 会不会是我对 DDMS 读数的解释有误,真的没有 900K block 可以分配?如果是这样,谁能告诉我在哪里可以看到?
非常感谢
梅曼
最佳答案
我认为你的情况没有什么特别之处。只是内存不够。内存中不能有多个 600x800 位图,它们会占用太多内存。您应该将它们保存到 SD 并按需加载到内存中。我认为这正是你所做的。
您应该注意的一件事:DDMS 显示 java 堆内存消耗。但也有未在 DDMS 中显示的 native 内存。据我所知,位图是在 native 内存中创建的。所以 DDMS 只是一个不好的工具来跟踪这些内存问题。您只需要确保释放内存,垃圾收集器会在您不再需要图像后收集它们。
垃圾收集器按自己的时间表工作。这就是为什么您应该在不再需要的位图上调用 Bitmap.recycle() 方法。此方法完全释放您用完的 native 内存。这样就不用依赖 GC 了,可以尽快释放最大的一 block 内存。
首先你应该确保你不会泄露位图。
这是一个不错的 post关于内存分配,它可以帮助您更深入地挖掘
关于Android:OutofMemoryError:位图大小超出 VM 预算,我看不到任何理由,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3037027/