java - 如何避免 java.lang.OutOfMemoryError : bitmap size exceeds VM budget in android while using a large bitmap?

标签 java android memory bitmap

我意识到有很多类似的问题,但大多数涉及缩小位图,或显式调用 bitmap.recycle() 和 System.gc() 这不能保证任何事情(在我的情况下未能阻止错误)。

编辑:我也曾尝试在创建位图时使用 isPurgable = true。

编辑:另外,我只在 Motorola Droid 上用 Froyo (2.2.2) 测试过这个。

场景如下:我正在加载一个位图(宽度:1500,高度:2400)。这大约占用 14 MB。该应用程序的其余部分在内存消耗方面微乎其微(很容易低于 2 MB)。

我使用带有变换矩阵的位图在表面 View 上平移和缩放。在第一次加载时,这完美地工作。但是,当我退出应用程序并重新启动它时,我得到了可怕的 OutOfMemoryError。第三次启动它工作,第四次它崩溃......等等。

我不需要保存状态,所以我尝试在 onPause() 中调用 finish() (以及上面提到的 recycle() 和 gc() 方法)。 Finish() 似乎停止了所有线程,但并未清除内存。

我应该提一下,我也在使用我在 this question 的评论中找到的技术。 . 另请查看 this

所以,我的图片是从网络上加载的,作为一个不可变的位图。然后将其字节保存到 sdcard(非常慢),只是为了重新加载回可变位图。如果跳过所有这些箍是可笑的,请教育我...

就我而言,清除为应用程序分配的所有内存是可以接受的(如果它不生成崩溃消息)。有没有办法完全清除分配给我的应用程序的内存,以便每次重新启动都像第一次启动一样干净?

有没有涉及平铺的解决方案?我肯定遗漏了一些东西.. 因为图像文件本身 (png) 只有几千字节,而且我在图库应用程序中查看更大的图像时没有这个问题。

编辑:我已经根据从@Jason Lebrun 的回答中收集到的见解确定了问题的原因。事实证明,我用来在此位图上绘制的 Canvas 也包含一个引用,因此需要将 Canvas 设置为 null 才能正确地进行垃圾回收。希望这对遇到类似问题的人有所帮助。

最佳答案

您是在 Gingberbread 还是其他版本上遇到此问题? Gingerbread 在使用大量位图内存的应用程序中存在很多问题,因此了解操作系统版本有助于确定问题的性质。

在您的情况下,很难确切说明可能是什么原因。但是,对于 14MB 的位图,即使是第二个实例也可能会用完可用的堆并导致崩溃。在 Gingerbread 上,由于并发 GC + Bitmap 内存是在 native 数组中分配的事实,很容易导致 Bitmap 内存停留的时间超过应有的时间。

当您退出应用程序时,它可能并未从内存中卸载。这可以解释您的崩溃模式:第一次运行该应用程序时,会加载大位图。第二次启动它时,它实际上只是为已经在内存中的进程重新启动一个 Activity,并且由于某种原因,Bitmap 的内存仍在占用空间。所以应用程序崩溃了,一个新的进程开始了,有一个新的堆。如果回收无济于事,您可能仍然保留对先前位图的引用。如果您总是使用同一个位图,重复使用对它的静态引用可能会有所帮助,尽管我不确定。

您确定位图没有通过泄漏的上下文、长时间运行的后台代码或类似的东西泄漏吗?

这里的其他答案有很好的建议,即在获取位图后尝试平铺位图,并且只在必要时加载平铺。如果不需要支持旧版本,可以使用 BitmapRegionDecoder (http://developer.android.com/reference/android/graphics/BitmapRegionDecoder.html) 来实现,但仅限于支持 API 级别 10 或更高级别的设备。

关于java - 如何避免 java.lang.OutOfMemoryError : bitmap size exceeds VM budget in android while using a large bitmap?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9950744/

相关文章:

java - Spring Integration、JMS 入站 channel 适配器和事务

java - 运行 HashMap 中的对象的方法

java - 数组/链表 : performance depends on the *direction* of traversal?

android - 操作系统的语言可能会影响Android SDK的安装?

c - 从 Linux 内核模块共享内存以供用户空间进程访问

java - 即使使用 UTF-8,为什么 ¿ 在 Windows 和 Linux 中显示不同?

java - 如何将时间转换为 UTC,然后转换为设备本地时间

android - 没有主构造函数就不可能进行父类(super class)型初始化

iphone - 没有声音在播放

android - 由于内存使用率高,应用程序崩溃