安卓的OutOfMemoryError:位图大小超过VM预算,没有任何理由,我可以看到位图、可以看到、预算、大小

2023-09-12 02:01:44 作者:奶嘴,还我初吻@

我有一个内存溢出异常画廊在600X800像素的JPEG的。

I am having an OutOfMemory exception with a gallery over 600x800 pixels JPEG's.

环境

我一直在使用画廊与JPG图片论坛围绕600X800像素。

I've been using Gallery with JPG images around 600x800 pixels.

由于我的内容可能有点不只是图像更复杂,我已经设置每个视图是一个RelativeLayout的一个包装的ImageView与JPG。

Since my content may be a bit more complex than just images, I have set each view to be a RelativeLayout that wraps ImageView with the JPG.

在以加快的用户体验,我有4个插槽,prefetches(在一个活套)约1的图像左,1形象权所显示的图像,并让他们在4插槽的简单缓存HashMap中。

In order to "speed up" the user experience I have a simple cache of 4 slots that prefetches (in a looper) about 1 image left and 1 image right to the displayed image and keeps them in a 4 slot HashMap.

平台

我使用256的RAM和128堆大小AVD,具有600X800的屏幕。 它也发生在随行人员边缘的目标,不同的是该设备是难以调试。

I am using AVD of 256 RAM and 128 Heap Size, with a 600x800 screen. It also happens on an Entourage Edge target, except that with the device it's harder to debug.

问题

我已经获得了异常:

OutofMemoryError: bitmap size exceeds VM budget

和它取第五图像时发生。我试图改变我的形象高速缓存的大小,它仍然是相同的。

And it happens when fetching the fifth image. I have tried to change the size of my image cache, and it is still the same.

奇怪的:不应该有一个内存问题

为了确保堆限制是非常远离我需要什么,我已经定义在开始一个虚拟8MB数组,离开它未引用,所以它立即出动。它是活动线程的成员,并且被定义为以下

In order to make sure the heap limit is very far away from what I need, I have defined a dummy 8MB array in the beginning, and left it unreferenced so it's immediately dispatched. It is a member of the activity thread and is defined as following

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

其结果是,堆的大小几乎是11MB,这一切都是免费的。 注意的我加那招后,开始崩溃。它使内存溢出的不那么频繁。

The result is that the heap size is nearly 11MB and it's all free. Note I have added that trick after it began to crash. It makes OutOfMemory less frequent.

现在,我使用DDMS。就在崩溃(不改变崩溃后多),DDMS显示:

Now, I am using DDMS. Just before the crash (does not change much after the crash), DDMS shows:

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中说:

The largest block is 7.7MB. And yet the LogCat says:

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

如果您介意中位数和平均数的关系,它是合理的假设,大多数可用的块是非常小的。然而,有一个块足够的位图大,这是7.7M。为什么它仍然是不够的?

If you mind the relation of the median and the average, it is plausible to assume that most of the available blocks are very small. However, there is a block large enough for the bitmap, it's 7.7M. How come it is still not enough?

注:我录了一堆跟踪。在查看数据的分配量,但不觉得2M以上分配。它匹配DDMS可用内存报告。

Note: I recorded a heap trace. When looking at the amount of data allocated, it does not feel like more than 2M is allocated. It does match the free memory report by DDMS.

难道是我遇到像堆碎片的一些问题? 如何解决/解决方法的问题? 共享给所有线程堆? 难道是我除preT的DDMS读出了错误的方式,而且确实没有900K块分配?如果是的话,有谁能够告诉我在哪里可以看到?

多谢

Meymann

推荐答案

我觉得没有什么特别的你的情况。只是有没有足够的内存。你不能有多个600X800位图在内存中,它们消耗了太多的内存。你应该将它们保存到SD和加载到内存的需求。我想,这正是你做的。

I think there's nothing special in your case. There's just not enough memory. You can't have several 600x800 bitmaps in memory, they consume too much memory. You should save them to SD and load to memory on demand. I think that's exactly what you do.

有一件事你应该知道的:DDMS显示Java堆内存的消耗。但也有未在DDMS显示本机内存。和位图据我理解,只在本机内存中创建。所以DDMS仅仅是一个坏的工具来跟踪这些内存问题。你只需要确保你释放你的记忆,即图像收集的垃圾收集后,你不需要他们了。

One thing you should be aware of: DDMS displays java heap memory consumption. But there's also native memory that is not displayed in DDMS. And bitmaps as far as I understand are created in native memory. So DDMS is just a bad tool to track these memory issues. You just need to be sure that you free your memory, that images are collected by Garbage Collector after you don't need them any more.

垃圾收集器适用于它自己的时间表。这就是为什么你要叫Bitmap.recycle()位图的方法,你不需要任何更多。这种方法可以释放完全,你跑出来的本机内存。这样,你不依赖于GC,您可以尽快释放内存的最大的一块地。

Garbage Collector works on it's own schedule. That's why you should call Bitmap.recycle() method on bitmaps that you don't need any more. This method frees exactly the native memory that you run out of. This way you don't depend on GC and you can free largest piece of memory as soon as possible.

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

First of all you should ensure that you don't leak bitmaps.

下面是一个不错的post在内存分配,它可以帮助你深入挖掘

Here's a nice post on memory allocations, it can help you to dig deeper