我意识到有很多类似的问题,但大多数涉及缩小位图,或显式调用 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/