Android 我快发疯了
我已经做了很多搜索,我认识很多其他人 与Android 我快发疯了,android,out-of-memory,android-bitmap,Android,Out Of Memory,Android Bitmap,我已经做了很多搜索,我认识很多其他人 与位图工厂遇到相同的OOM内存问题。我的 应用程序仅使用Runtime.getRuntime显示4MB的总可用内存 ().totalMemory()。如果限制为16MB,那么为什么总数不为16MB 内存增长为位图腾出空间?相反,它会抛出一个错误 我也不明白如果我有1.6MB的可用内存 到Runtime.getRuntime().freemory()为什么会出现错误,说“VM” 不让我们分配614400字节“?在我看来,我有很多 可用内存 我的应用程序是完整的
位图工厂
遇到相同的OOM内存问题。我的
应用程序仅使用Runtime.getRuntime显示4MB的总可用内存
().totalMemory()
。如果限制为16MB,那么为什么总数不为16MB
内存增长为位图腾出空间?相反,它会抛出一个错误
我也不明白如果我有1.6MB的可用内存
到Runtime.getRuntime().freemory()
为什么会出现错误,说“VM”
不让我们分配614400字节“?在我看来,我有很多
可用内存
我的应用程序是完整的,除了这个问题,当我
重新启动手机,使我的应用程序成为唯一正在运行的程序。我正在使用
用于设备测试的HTC英雄(安卓1.5)
在这一点上,我想唯一的办法就是
避免使用BitmapFactory
有没有人对此有什么想法,或者解释一下为什么VM不会这样做
当有1.6MB的可用内存时分配614KB?1.6MB的内存似乎很多,但可能是内存碎片严重,无法一次性分配如此大的内存块(这听起来还是很奇怪) 在使用图像资源时出现OOM的一个常见原因是解压缩分辨率非常高的JPG、PNG、GIF图像。您需要记住,所有这些格式都经过了很好的压缩,占用的空间非常小,但一旦您将图像加载到手机中,它们将使用的内存类似于
width*height*4字节
。此外,当解压开始时,需要为解码步骤加载一些其他辅助数据结构。[请注意(正如Commonware在下面指出的那样),此答案中的整个方法仅适用于2.3.x(姜饼)。从那时起,蜂窝位图数据在VM堆中分配。]
位图数据未在VM堆中分配。在VM堆中有一个对它的引用(它很小),但实际数据是由底层Skia图形库在本机堆中分配的 不幸的是,虽然BitmapFactory.decode…()的定义指出,如果图像数据无法解码,它将返回null,但Skia实现(或者更确切地说,Java代码和Skia之间的JNI胶水)会记录您看到的消息(“VM不允许我们分配xxxx字节”)然后抛出一个OutOfMemory异常,错误消息为“位图大小超过VM预算” 问题不在VM堆中,而是在本机堆中。Natïve堆在正在运行的应用程序之间共享,因此可用空间的大小取决于其他正在运行的应用程序及其位图使用情况。但是,考虑到BitmapFactory不会返回,您需要一种方法在调用之前确定调用是否会成功 有一些例程可以监视本机堆的大小(请参阅调试类getNative方法)。但是,我发现getNativeHeapFreeSize()和getNativeHeapSize()不可靠。因此,在我的一个动态创建大量位图的应用程序中,我执行以下操作 本机堆大小因平台而异。因此,在启动时,我们检查允许的最大VM堆大小,以确定允许的最大本机堆大小。[幻数是通过在2.1和2.2上测试确定的,在其他API级别上可能不同。]
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时,我们都会在调用之前检查表单
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。虽然捕获错误通常没有意义,因为它们通常仅由vm引发,但在这种特殊情况下,错误由jni glue代码引发,因此处理无法加载图像的情况非常简单:只捕获OutOfMemoryError 虽然这是一个相当高级别的答案,但对我来说,问题是在所有视图中使用硬件加速。我的大多数视图都有自定义位图操作,我认为这是大型本机堆大小的来源,但事实上,当禁用硬件加速时,本机堆的使用量减少了4倍
硬件加速似乎可以在视图上进行各种缓存,创建自己的位图,而且由于所有位图都共享本机堆,分配大小可能会急剧增加。中给出的问题似乎已在较新版本的Android中得到解决 但是,如果您使用的是图像缓存(一个专门的缓存,甚至只是一个普通的HashMap),则很容易通过创建内存泄漏来获得此错误 根据我的经验,如果您无意中保留引用并造成内存泄漏,OP的错误(引用和本机方法)将导致应用程序崩溃(最多可达ICS-14和+?) 要避免这种情况,请让您的用户“放开”位图。这意味着在缓存的最后一层使用软引用,以便位图可以从中回收垃圾。这应该是可行的,但如果您仍然遇到崩溃,您可以尝试使用显式标记某些位图以供收集,但请记住,如果需要,永远不要返回位图以在应用程序中使用
顺便说一句,是一个很好的工具,可以轻松实现非常好的缓存结构,特别是如果您将硬引用和软引用结合在一起,比如。。。但如果你陷入困境,使用硬引用也会让你自己陷入内存泄漏的境地。这是一个非常有趣和实用的方法。有趣的帖子。你对此有什么证据/来源吗?:“Natïve堆在运行的应用程序之间共享,因此