BitmapFactory OOM 快把我逼疯了 [英] BitmapFactory OOM driving me nuts

查看:32
本文介绍了BitmapFactory OOM 快把我逼疯了的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经做了很多搜索,我认识很多其他人BitmapFactory 遇到了同样的 OOM 内存问题.我的应用程序使用 Runtime.getRuntime 仅显示 4MB 的总可用内存().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.

除此问题外,我的应用程序已完成,当我重新启动手机,以便我的应用程序是唯一运行的东西.我正在使用用于设备测试的 HTC Hero(Android 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 不会有 1.6MB 空闲内存时分配 614KB?

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 (Gingerbread).从蜂窝位图数据开始分配在 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图形库分配在Native堆中的.

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.decode...() 的定义说如果图像数据无法解码,它返回 null,Skia 实现(或者更确切地说是 Java 代码和 Skia 之间的 JNI 胶水)记录了消息您看到(VM 不会让我们分配 xxxx 字节")然后抛出 OutOfMemory 异常,并带有误导性消息位图大小超出 VM 预算".

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 堆中,而在本机堆中.Natïve 堆在运行的应用程序之间共享,因此可用空间量取决于正在运行的其他应用程序及其位图使用情况.但是,鉴于 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.

有一些例程可以监控 Native 堆的大小(参见 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.

本机堆大小因平台而异.因此,在启动时,我们会检查允许的最大 VM 堆大小以确定允许的最大 Native 堆大小.[幻数是通过在 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 时,我们都会在调用之前检查表单.

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 是一个神奇的数字,以允许以下事实:a) 本机堆大小的报告是软"的,并且 b) 我们希望在本机堆中为其他应用程序留出一些空间.我们目前使用 3*1024*1024(即 3Mbytes)的 pad 运行.

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.

这篇关于BitmapFactory OOM 快把我逼疯了的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆