【问题标题】:Android not freeing Bitmap from memoryAndroid没有从内存中释放位图
【发布时间】:2013-09-21 20:19:47
【问题描述】:

我已经做了以下事情来处理我的应用程序中的位图:

  1. LruCache 用于 Bitmaps,大小为内存的 1/8
  2. 使用BitmapFactory.Options计算inSampleSize
  3. 在创建Bitmaps时捕获OOM,在那里调用evictAllSystem.gc()
  4. 还有AsyncTask 解码有时用于Bitmaps

我使用BitmapFactory.decodeFile,看起来VM 从内存中释放Bitmaps 的速度不够快。我在某处读到使用BitmapFactory.decodeFile 可能存在错误,所以我尝试使用BitmapFactory.decodeFileDescriptor,但我随机得到以下信息:

skia --- 解码器->解码返回假

如果我不想使用BitmapFactory.decodeFileDescriptor 或其他事情要做,那么FileInputStream 是否有问题需要在这里修复。

这花了我太多时间,我已经阅读了基于此的所有解决方案以及 Google 建议 Bitmap 处理的方式,但我已经走到了死胡同。

谢谢。

【问题讨论】:

  • 你想用Bitmaps做什么?如果你问这个问题,我相信你加载了很多
  • 我怀疑您在 listview 或 gridview 中使用位图,它会导致 OutOfMemoryError。如果是这种情况,您应该考虑位图的弱引用。你能进一步阐述你的场景吗
  • 在 ListView 和 GridView 中,也可以全屏缩放
  • 请查看此链接github.com/nostra13/Android-Universal-Image-Loader 我认为这可能对您有所帮助。
  • 我们公司的政策不允许任何第三方库。

标签: android memory-management bitmap out-of-memory


【解决方案1】:

使用大位图总是有机会出现内存不足异常.. 所以要通过Android博客来处理

http://developer.android.com/training/displaying-bitmaps/index.html

并且始终回收 Bimap

ImageView mImage;
Drawable toRecycle = mImage.getDrawable();
        if ( toRecycle != null && toRecycle instanceof BitmapDrawable ) {
            if ( ( (BitmapDrawable) mImage.getDrawable() ).getBitmap() != null )
                ( (BitmapDrawable) mImage.getDrawable() ).getBitmap().recycle();
        }

【讨论】:

  • 这看起来很讨厌,平台不应该在没有在任何地方使用时自动回收该位图吗?
  • 我所有的位图都在 LruCache 中,所以我正在寻找更通用的答案,其中位图回收发生在一个地方,而不是基于一个 ImageView 位图的单一解决方案。
【解决方案2】:

我最终在这里使用了SoftRefencesBitmap。现在我可以看到 GC 在快速滚动 GridView 时一直释放我未使用的 Bitmaps 来吸引它们。

测试设置我的LruCache size 全内存大小,仍然没有得到OOM。

使用这种方法的惩罚不是那么明显,我的GridView 滚动非常流畅,因为它正在绘制非常自定义的图像。

【讨论】:

  • 应该始终使用 SoftReferences,否则 gc 仍然认为位图仍在使用,因为它的引用当前被内存中的某物持有。
【解决方案3】:

System.gc() 不会帮助您,也不保证任何事情。

如果您绝对确定,不再需要被逐出的位图并且在任何地方都没有引用它们(否则会捕获“无法绘制回收的位图”异常)我建议您将 EvictionListener 添加到您的 LRU 缓存和对每个被驱逐的值调用 bitmap.recycle()。

不记得默认的 LRU 缓存是否提供了设置驱逐监听器的便捷方法,但如果没有,扩展它并添加所需的功能非常容易。

附:我建议不要使用 Wea​​kReferences,因为您失去了对位图和 LRU 目的的任何控制。即使您加载 8 个位图,它们很好地适合您的 1/8 内存,但屏幕一次只能显示其中 4 个(ImageViews 对位图有很强的引用)gc 会尽快清除剩余的 4 个。我的意思是超快。您必须为正在显示的每个新行(在 ListView 的情况下)重新加载位图。而且每一个离开屏幕的位图都必须重新加载。

【讨论】:

  • 我可以覆盖 LruCache 上的 entryRemoved,但我不知道如何以 100% 的保证检测位图未在某处使用,我可以调用它回收。那么,WeakReference 是否会成为不错的选择,因为 GC 可能会将其检测为垃圾和空闲内存?
  • 为什么觉得gc跟不上,会OOM吗?
  • 1/8 是很小的内存量。您需要在短时间内加载大量位图以使其溢出太多,以至于您得到 OOM
  • 是的,我确实得到了 OOM,也许我的 LruCache 位图的 SoftReferences 可以让 GC 更难理解释放内存?
  • 嗯,这意味着 List with WeakReferences 是你最好的选择,在这种情况下使用 LRU 是没有意义的,因为你的位图是由引用控制的,而不是由 LRU 算法控制的。
猜你喜欢
  • 2019-01-20
  • 1970-01-01
  • 2017-09-22
  • 1970-01-01
  • 2019-08-12
  • 2015-09-29
  • 2016-01-28
  • 2016-02-09
  • 1970-01-01
相关资源
最近更新 更多