BitmapFactory OOM我发疯BitmapFactory、OOM

2023-09-11 11:27:18 作者:Last(最后)

我已经做了很多搜索的,我知道很多其他人 遇到与 BitmapFactory 相同的OOM内存问题。我的 程序只显示可用4MB的使用总内存调用Runtime.getRuntime ().totalMemory()。如果限制为16MB,那么为什么不总 内存增长腾出空间为位图?相反,它抛出一个错误。

I've been doing a lot of searching and I know a lot of other people are experiencing the same OOM memory problems with BitmapFactory. My app only shows a total memory available of 4MB using Runtime.getRuntime ().totalMemory(). If the limit is 16MB, then why doesn't the total memory grow to make room for the bitmap? Instead it throws an error.

我也没有根据的可用内存,如果我有1.6MB的理解 以调用Runtime.getRuntime()。freeMemory()为什么我得到一个错误说VM 不会让我们分配614400字节?在我看来,我有足够 可用内存。

I also don't understand that if I have 1.6MB of free memory according to Runtime.getRuntime().freeMemory() why do I get an error saying "VM won't let us allocate 614400 bytes"? Seems to me I have plenty available memory.

我的应用程序是完整的,除了这个问题,这消失的时候我 重启手机,这样我的应用程序是东西只运行。我使用 在宏达英雄的设备测试(安卓1.5)。

My app is complete except for this problem, which goes away when I reboot the phone so that my app is the only thing running. I'm using an HTC Hero for device testing (Android 1.5).

在这一点上我想解决这个问题的唯一办法就是以某种方式 避免使用 BitmapFactory

At this point I'm thinking the only way around this is to somehow avoid using BitmapFactory.

任何人有任何想法或解释为什么VM将不 分配614KB当有空闲内存1.6MB?

Anyone have any ideas on this or an explanation as to why VM won't allocate 614KB when there's 1.6MB of free memory?

推荐答案

[注意(如CommonsWare指出,下同)在这个答案的整个方法只适用于截至及包括2.3.x(姜饼)。作为蜂窝位图数据被分配在VM堆。]

[Note that (as CommonsWare points out below) the whole approach in this answer only applies up to and including 2.3.x (Gingerbread). As of Honeycomb Bitmap data is allocated in the VM heap.]

位图数据不分配在VM堆。有对它的引用在VM堆(这是小),但实际的数据是通过底层Skia的图形库分配的本地堆

Bitmap data is not allocated in the VM heap. There is a reference to it in the VM heap (which is small), but the actual data is allocated in the Native heap by the underlying Skia graphics library.

不幸的是,同时BitmapFactory.de code)中定义...(说它如果图像数据不能德$ C $光盘,所述Skia的实现(或者更确切地说之间的JNI的胶水返回null Java的code和Skia的)记录你看到的消息(虚拟机不会让我们分配XXXX字节),然后抛出内存不足异常与误导信息位图大小超过虚拟机的预算。

Unfortunately, while the definition of BitmapFactory.decode...() says that it returns null if the image data could not be decoded, the Skia implementation (or rather the JNI glue between the Java code and Skia) logs the message you’re seeing ("VM won't let us allocate xxxx bytes") and then throws an OutOfMemory exception with the misleading message "bitmap size exceeds VM budget".

这个问题是不是在VM堆相反却是在本机堆。本机堆正在运行的应用程序之间共享,这样的自由空间量取决于其他应用程序正在运行什么,以及他们的位图的使用。但是,考虑到BitmapFactory将不会返回,您需要一种方法来计算出,如果呼叫要你做之前成功。

The issue is not in the VM heap but is rather in the Native heap. The Natïve heap is shared between running applications, so the amount of free space depends on what other applications are running and their bitmap usage. But, given that BitmapFactory will not return, you need a way to figure out if the call is going to succeed before you make it.

有程序来监视本机堆的大小(请参阅Debug类getNative方法)。但是,我已发现,getNativeHeapFreeSize()和getNativeHeapSize()是不可靠的。因此,在我的应用程序将动态创建大量位图我做以下。

There are routines to monitor the size of the Native heap (see the Debug class getNative methods). However, I have found that getNativeHeapFreeSize() and getNativeHeapSize() are not reliable. So in one of my applications that dynamically creates a large number of bitmaps I do the following.

本机堆的大小因平台而异。因此,在启动时,我们检查的最大允许虚拟机堆大小,以确定最大允许本地堆大小。 [该幻数是通过测试在2.1和2.2来确定,并且可以是在其它的API级的不同。]

The Native heap size varies by platform. So at startup, we check the maximum allowed VM heap size to determine the maximum allowed Native heap size. [The magic numbers were determined by testing on 2.1 and 2.2, and may be different on other API levels.]

long mMaxVmHeap     = Runtime.getRuntime().maxMemory()/1024;
long mMaxNativeHeap = 16*1024;
if (mMaxVmHeap == 16*1024)
     mMaxNativeHeap = 16*1024;
else if (mMaxVmHeap == 24*1024)
     mMaxNativeHeap = 24*1024;
else
    Log.w(TAG, "Unrecognized VM heap size = " + mMaxVmHeap);

然后每次我们需要调用BitmapFactory时候我们precede的呼吁形式的检查。

Then each time we need to call BitmapFactory we precede the call by a check of the form.

long sizeReqd        = bitmapWidth * bitmapHeight * targetBpp  / 8;
long allocNativeHeap = Debug.getNativeHeapAllocatedSize();
if ((sizeReqd + allocNativeHeap + heapPad) >= mMaxNativeHeap)
{
    // Do not call BitmapFactory…
}

请注意,该heapPad是一个神奇的数字,以便对这样一个事实)的本地堆大小的报告是软和b)我们要留有一定的空间,在机堆的其他应用程序。我们有3 * 1024 * 1024(即3Mbytes)垫当前正在运行。

Note that the heapPad is a magic number to allow for the fact that a) the reporting of Native heap size is "soft" and b) we want to leave some space in the Native heap for other applications. We are running with a 3*1024*1024 (ie 3Mbytes) pad currently.