【问题标题】:Finding the "killer" memory caching mechanism for Android [closed]寻找 Android 的“杀手”内存缓存机制 [关闭]
【发布时间】:2013-01-12 06:53:11
【问题描述】:

背景

Android 的最大堆大小非常有限,每个设备都有不同的最大堆。

某些应用需要能够在内存中缓存内容(通常是图像),而不仅仅是在内部/外部存储中。

当然,nice tips 很多关于处理位图和使用尽可能少的内存,但缓存也是必要的。

问题

我已经阅读了许多可能的缓存解决方案,但没有一个提供一种可以成为杀手级缓存解决方案的缓存。我想要的是具有以下功能的缓存机制:

  1. 无限使用堆,不用担心内存不足。应用程序需要内存并且没有足够的可用内存?所以释放一些(未引用的)项目(及其密钥)。

  2. 线程安全/并发。

  3. 提供基于 LRU 的缓存,以便最近使用的项目有更高的保留机会。

  4. 尽可能保持活力(但不会导致任何崩溃)。然而,遗憾的是,在 Android 上,与 Java 相比,软/弱引用的 GC 速度非常快。

  5. 能够处理隐藏其实际大小的对象。在 Android 上,在 API 10 及更低版本上,位图不使用堆内存,但被认为是这样的,因此 VM 无法知道何时释放它们,因为它认为使用与单个引用相同的内存量(4字节左右)。这就是为什么一些解决方案可以人为地判断每个项目的大小,以及何时需要移除它。

一些不错的可能解决方案

  1. LruCache - API 12 中的一个类(不过,您可以轻松复制其代码)。

    优势:#2 (?)、#3、#5。

    缺点:#1、#4,加上你需要复制它的源代码,因为它是在 API 12 上呈现的。

  2. 其值具有软/弱引用的哈希图,如第 50 页上的here 所示,取自this lecture

    优点:#1(但不删除键),#2(需要使用ConcurrentHashMap

    缺点:#3、#4、#5

  3. MapMaker(可从the guava library获得),类似于之前解决方案的高级版本。

    优点:#1、#2

    缺点:#3、#4、#5

  4. Caching solutions 通过 guava 库。优点和缺点取决于您的选择。不确定哪种配置最适合需求,以及它是否在 Android 上运行良好。遗憾的是,我什至无法为 Android 编译库。

  5. Android query - 不确定它是如何工作的。看起来很容易使用,但不确定它的优缺点。

问题

有人知道杀手级缓存机制吗?

我不太关心功能 #5,因为它非常先进,并且随着越来越多的人拥有更新的 Android 版本,将来不会那么需要。

【问题讨论】:

  • 它是封闭的和过时的,但这是 android 性能的一个非常重要的方面,没有得到足够的讨论,特别是对于像位图这样的大对象。 Picasso 库对图像进行自动缓存,如果需要,您可以扩展它们的缓存大小。

标签: android caching bitmap out-of-memory heap-memory


【解决方案1】:

正如我所见,#1 存在一个实际的禁止问题。您不能释放从应用程序的其他部分引用的对象;因此,不可能创建一个随意释放内存的构造。

我看到的唯一解决方案是创建自己的支持 LRU 并能够处理弱引用和强引用的缓存。一个项目开始是一个强引用的东西,如果有一段时间不使用,或者强制执行内存限制,你可以将它更改为弱引用。这并不容易创建,并且必须确保在所有应用程序中都进行微调。

【讨论】:

  • 不,你不明白。我的意思是您作为开发人员不需要关心何时清除缓存(从未引用的项目中),或设置关于其大小的边界。它会自动执行所有操作,并使用尽可能多的内存,但它会在应用需要时释放内存(例如,使用软/弱引用)。
  • 我认为这正是我所描述的 :) 我提出的问题是,您可以应用启发式方法在缓存中明智地使用强引用和弱引用,但您仍然不会影响是否一个对象是否被释放。这取决于是否有来自 GC 根的强引用路径。您将始终需要处理 OOM,您只能减少需要处理的可能性。选择好的启发式可以创造奇迹。
  • 不,如果您只对放入缓存的对象使用弱/软引用,则在创建新对象时不应出现内存不足异常(当然,除非它们具有强引用),因为当 gc 注意到没有足够的内存来保存所有内容时,它会清理它们。这是一种非常安全的方式,但遗憾的是,即使内存足够,android 也会经常释放此类对象。
  • 这是我试图解释的。整个事情取决于您的应用程序是否表现良好。它是让未使用的缓存对象释放还是保留对它们的强引用。仅靠弱引用并不能确保任何事情。您仍然可以收到 OOM。正是因为 Android 过于急切地释放弱引用对象,所以您应该采用一些启发式方法,并在缓存中保留对您想要保留在那里的对象的强引用。但如果内存饱和,缓存应该智能地开始更改为弱引用。正确实现这非常复杂。
  • 这就是为什么我要求为 android 提供一个好的解决方案。因为它很复杂,我认为我找不到一个好的解决方案。一些解决方案(如番石榴库)我什至无法尝试,因为它们不能开箱即用。
【解决方案2】:

您可能正在寻找更通用的解决方案,但如果您主要关注图像,请查看ImageLoader。我已经使用了一段时间,它非常适合我需要的东西。初始化时,您可以告诉它使用 LRUCache 并告诉它要使用的可用内存百分比。

顺便说一句,HttpResponseCache 使得缓存来自服务器的数据非常非常好。

【讨论】:

  • 如果我错了,请纠正我,但问题是它是有界的。它也不会在需要时释放内存,只有当它超过我给它的最大内存量时。所以这就像我提到的解决方案#1。
【解决方案3】:

看看Android BitMap Cache,它是LruCache 的一个大大改进的版本。

http://www.senab.co.uk/2013/01/24/android-bitmapcache-v2-1/

【讨论】:

  • 不错,但是根据这个库的gridView的示例,它没有特征#4,这意味着图像很早就被释放了,所以很少使用内存缓存。另外,该示例存在根本不显示某些图像的错误,并且此解决方案仅适用于位图。
猜你喜欢
  • 2010-10-09
  • 2012-07-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-03-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多