Android:OutofMemoryError:位图大小超出虚拟机预算,我看不到任何原因

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3037027/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-20 08:24:27  来源:igfitidea点击:

Android: OutofMemoryError: bitmap size exceeds VM budget with no reason I can see

androidgalleryimageviewout-of-memoryddms

提问by Meymann

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

我有一个 OutOfMemory 异常,其中一个画廊超过 600x800 像素的 JPEG。



The environment

环境

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

我一直在使用带有 600x800 像素左右的 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.

由于我的内容可能比图像更复杂一些,我将每个视图设置为一个用 JPG 包装 ImageView 的 RelativeLayout。

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.

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

The platform

该平台

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.

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



The problem

问题

I have been getting an exception:

我遇到了一个例外:

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.

它发生在获取第五张图像时。我试图改变我的图像缓存的大小,它仍然是一样的。



The strange thing: There should not be a memory problem

奇怪的是:应该不是内存问题

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

为了确保堆限制与我需要的相差很远,我在开始时定义了一个 8MB 的虚拟数组,并且不引用它,因此它会立即被调度。它是活动线程的成员,定义如下

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

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

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

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

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

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

And in the detail table it shows:

在详细表中,它显示:

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

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

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

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

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?

如果您介意中位数和平均值的关系,则可以假设大多数可用块非常小。但是,对于位图来说有一个足够大的块,它是 7.7M。怎么还是不够?

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.

注意:我记录了堆跟踪。看分配的数据量,感觉没有分配2M多。它确实与 DDMS 的可用内存报告相匹配。



  • Could it be that I experience some problem like heap-fragmentation?
  • How do I solve/workaround the problem?
  • Is the heap shared to all threads?
  • Could it be that I interpret the DDMS readout in a wrong way, and there is really no 900K block to allocate? If so, can anybody please tell me where I can see that?
  • 难道我遇到了一些问题,比如堆碎片?
  • 我如何解决/解决问题?
  • 堆是否共享给所有线程?
  • 会不会是我对DDMS读数的理解错误,真的没有900K块可以分配?如果是这样,有人可以告诉我在哪里可以看到吗?

Thanks a lot

非常感谢

Meymann

迈曼

采纳答案by Fedor

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.

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

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.

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

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.

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

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

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

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

这是一篇关于内存分配的好文章,它可以帮助您深入挖掘

回答by Fedor

Not sure if it's an option for you, but have you tried supersampling images Strange out of memory issue while loading an image to a Bitmap object?

不确定它是否适合您,但是您是否尝试过对图像进行超级采样 将图像加载到位图对象时出现奇怪的内存不足问题

回答by Shailendra Singh Rajawat

I Also faced similar issue couple of weeks back and i solved it by scaling down images upto optimal point. I have written complete approach in my blog hereand uploaded complete sample project with OOM prone code vs OOM Proof code here.

几周前我也遇到了类似的问题,我通过将图像缩小到最佳点来解决它。我在我的博客写完整的方法在这里并上传完整的示例项目,OOM易码VS OOM证明代码在这里

回答by Meymann

There has been lots of time since I asked that.

自从我问那个以来已经有很多时间了。

The answer should be divided to 2 parts: Pre-Gingerbread: you just use small pictures, use subsampling, maybe one screen size photo, and hope for good. Try to make sure you don't allocate tiny items you can't free before getting a bitmap. Pre-Ginger, the memory for bmps had to be contonuous, and it was not counted in the VM memory. Always look at the logcat. See a lecture about memory from Google IO 2011. Post Ginger it's easier. Since Honeycomb, bitmaps are even counted in your java area. There is no jni area. Always use recycle for bitmaps you don't need. Don't wait for the GC.

答案应分为 2 部分: Pre-Gingerbread:您只使用小图片,使用二次采样,也许是一张屏幕大小的照片,并希望一切顺利。尝试确保在获取位图之前不要分配无法释放的小项目。Pre-Ginger,bmps 的内存必须是连续的,并且不计入 VM 内存。总是看logcat。请参阅 Google IO 2011 中有关内存的讲座。发布 Ginger 更容易。由于 Honeycomb,位图甚至计入您的 Java 区域。没有jni区。始终对不需要的位图使用回收。不要等待GC。

回答by Meymann

The question was asked in 2010, when Froyo was fresh. So many things happened since. Before 3.0, bitmaps were allocated in JNI. The memory didn't show in the Dalvik stats. It doesn't have to be monolithic anymore. Before 2.3, memory statistics for JNI were not available (bitmap decoding calls JNI) in logcat. 4.4 evacuated more space. 5.0 the big bang of Art. Back in 2010, Nexus One was high end, with less than 300MB. The budget for an app was around 16MB. Now days, there is about 8 times that memory.

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