Bitmap、Bitmap.recycle()、WeakReferences 和垃圾回收

Posted

技术标签:

【中文标题】Bitmap、Bitmap.recycle()、WeakReferences 和垃圾回收【英文标题】:Bitmap, Bitmap.recycle(), WeakReferences, and Garbage Collection 【发布时间】:2011-06-24 23:23:01 【问题描述】:

android 上 AFAIK,建议将 Bitmap 对象引用为 WeakReferences 以避免内存泄漏。当不再保留位图对象的硬引用时,垃圾收集器将自动收集它。

现在,如果我理解正确,必须始终调用 Bitmap.recycle() 方法来释放位图。我认为这是因为 Bitmap 对象具有特殊的内存管理。

对吗?

如果是这样,那么在使用 Wea​​kReferences 时,肯定会发生内存泄漏,因为在释放 WeakReferences 时永远不会调用 Bitmap.recycle()。或者,不知何故,WeakReferences 是否足以避免内存泄漏?

谢谢

【问题讨论】:

【参考方案1】:

Bitmap.recycle 不是必需被调用的,因为垃圾收集器最终会自行清理位图(只要没有引用)。 Android 中的位图是在本机内存中创建的,而不是在 VM 堆上,因此 VM 堆上的实际位图对象非常小,因为它不包含任何实际的位图数据。 (编辑:Android 3.0+ 不再是这种情况) 位图的实际大小仍将计入您的堆使用量,以用于 GC 并确保您的应用程序不会使用太多内存.

但是,GC 在位图方面似乎有点喜怒无常。如果您只是删除所有硬引用,它有时(在我的情况下)会在位图上挂起一段时间,这可能是因为位图对象的分配/计数方式很奇怪。 Bitmap.recycle 似乎有助于让 GC 更快地收集该对象。

无论哪种方式,只要您不意外保留硬引用,您就不会泄漏内存。但是,如果您尝试一次分配太多位图或未调用recycle 就分配了太大位图,您可能会遇到OutOfMemoryErrors

编辑:需要注意的是,从 Android 3.0 开始,位图不再分配在本机内存中。它们像任何其他 Java 对象一样分配在 VM 堆上。但是,我所说的不需要调用回收仍然适用。

【讨论】:

清除解释。非常感谢! 我以大约 20 秒的间隔加载图像。我调用 recycle() 但 Debug.getNativeHeapAllocatedSize() 表明本机内存分配不断增长,直到 OutOfMemoryError 这对于 android 3 上,您不必调用 recycle,但不得将任何对位图的引用保留在您的活动范围之外。 @Kevin: This 2011 Google I/O talk by Android engineer Patrick Dubroy disagrees. 是的,在 3.0 之前,Bitmaps 为本地堆上的像素数据分配了内存(我在原始帖子中提到过),Bitmap 的真实大小仍然是计入您的 VM 堆使用量。但是,它们仍然可以并且将被垃圾收集(最终,假设您没有持有硬引用),此时它们的终结器将运行并调用一个本机方法,该方法frees 本机堆上的内存。 现在,这并不意味着调用 recycle()、since it seems to take a few passes 让 GC 决定收集 3.0 之前的位图并调用它们的终结器不是一个好主意,如果你也分配在 GC 正确释放未使用的位图之前,如果位图太多或太大,您可能会遇到 OutOfMemoryErrors。但是,我对原始问题的回答(您 必须 调用 recycle 否则会泄漏内存)仍然准确,因为 3.0 之前的位图 最终 甚至会被 GC如果你不调用回收站。

以上是关于Bitmap、Bitmap.recycle()、WeakReferences 和垃圾回收的主要内容,如果未能解决你的问题,请参考以下文章

Android Honeycomb 中的 Bitmap#recycle() 实际上做了啥?

AsyncTask Android 中的致命信号 6 (SIGABRT)

Bitmap转圆形图片Bitmap

应对createjs编写的一些小方法

Bitmap占用内存大小的准确计算公式

Clickhouse的bitmap函数