10

我正在为我的 Android 应用程序实现缓存机制。

我使用SoftReference,就像我发现的许多示例一样。问题是,当我在 中向上或向下滚动时ListView大部分图像已经被清除。我可以在 LogCat 中看到每次应用程序加载新图像时都会对我的应用程序进行垃圾收集。这意味着大部分不可见的图像ListView都消失了。

因此,每次我滚动回较早的位置(我之前真正下载过图像的位置)时,我都必须再次下载图像 - 它们没有 被缓存

我也研究过这个话题。根据本文中的 Mark Murphy 的说法,似乎存在(或曾经是?)SoftReference. 其他一些结果表明相同的事情(或相同的结果);SoftReferences 清理得太早了。

有没有可行的解决方案?

4

5 回答 5

16

SoftReference 是可怜的 man Cache。JVM 可以使这些引用保持更长时间,但不是必须的。一旦不再有硬引用,JVM 就可以垃圾收集软引用的对象。您遇到的 JVM 的行为是正确的,因为 JVM 不必将此类对象保留更长时间。当然,大多数 JVM 都试图在一定程度上保持软引用对象的存活。

因此,SoftReferences 是一种危险的缓存。如果你真的想确保缓存行为,你需要一个真正的缓存。就像LRU-cache一样。特别是如果您的缓存对性能至关重要,您应该使用适当的缓存。

于 2011-04-22T17:18:17.527 回答
7

来自 Android 培训网站:

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

过去,流行的内存缓存实现是 SoftReference 或 WeakReference 位图缓存,但不建议这样做。从 Android 2.3(API 级别 9)开始,垃圾收集器更积极地收集软/弱引用,这使得它们 相当无效。此外,在 Android 3.0(API 级别 11)之前,位图的支持数据存储在本机内存中,无法以可预测的方式释放,可能导致应用程序短暂超出其内存限制并崩溃。

链接中的更多信息。

我们应该改用LruCache

于 2012-08-13T10:46:16.827 回答
2

将每个图像缓存在持久存储中,而不仅仅是在内存中。

于 2011-04-22T17:17:34.683 回答
1

Gamlor 的答案在您的情况下是正确的。但是,有关其他信息,请参阅GC 常见问题解答,问题 32。

Java HotSpot Server VM 使用最大可能的堆大小(由 -Xmx 选项设置)来计算剩余的可用空间。

Java HotSpot Client VM 使用当前堆大小来计算可用空间。

这意味着服务器 VM 的总体趋势是增加堆而不是刷新软引用,因此 -Xmx 对软引用何时被垃圾回收有显着影响。

于 2011-06-09T18:26:14.917 回答
0

Jvm 遵循这个简单的等式来确定是否应该清除软引用:

间隔 <= free_heap * ms_per_mb

间隔是上次 gc 循环时间戳和软引用的最后访问时间戳之间的持续时间。空闲堆是当时可用的堆空间。ms_per_mb 是分配给堆中每个可用 MB 的毫秒数。(恒定默认 1000 毫秒)

如果上述等式为假,则参考被清除。

因此,即使您有很多可用内存,如果您的软引用在很长一段时间内没有被访问,它们也会被清除。

-XX:SoftRefLRUPolicyMSPerMB= jvm arg 可用于调整 ms_per_mb 常量。

于 2020-07-31T14:31:45.253 回答