我正在为我的Android应用程序实现缓存机制。
我使用SoftReference
,就像我发现的许多例子一样。问题是,当我在ListView
中向上或向下滚动时,图像的最多已被清除。我可以在LogCat中看到每次应用程序加载新图像时我的应用程序都是垃圾回收。这意味着ListView
中不可见图像的最消失了。
所以,每当我向后滚动到之前的位置(之前我真的下载过图像)时,我必须再次下载图像 - 它们不 缓存
我也研究过这个话题。 According to Mark Murphy in this article,SoftReference
似乎存在(或者是?)错误。一些其他结果表明相同的事情(或相同的结果); SoftReference
过早被清除。
有没有可行的解决方案?
答案 0 :(得分:16)
SoftReference是可怜的勒芒。 JVM可以将这些引用保持更长时间,但不必。只要没有硬引用,JVM就可以垃圾收集软引用的Object。您遇到的JVM的行为是正确的,因为JVM不必更长时间地保持这样的对象。当然,大多数JVM都试图在某种程度上保持软参考对象的存活。
因此,SoftReferences是一种危险的缓存。如果您确实想要确保缓存行为,则需要一个真正的缓存。像LRU-cache一样。特别是如果你的缓存是性能关键的,你应该使用适当的缓存。
答案 1 :(得分:7)
来自Android培训网站:
http://developer.android.com/training/displaying-bitmaps/cache-bitmap.html
过去,流行的内存缓存实现是SoftReference 或WeakReference位图缓存,但不建议这样做。 从Android 2.3(API Level 9)开始,垃圾收集器更多 积极收集软/弱参考,使他们 相当无效。此外,在Android 3.0(API Level 11)之前, 位图的后备数据存储在本机内存中,而不是 以可预测的方式发布,可能导致应用程序 短暂地超过其记忆限制和崩溃。
链接中的更多信息。
我们应该使用LruCache代替。
答案 2 :(得分:2)
将每个图像缓存在持久存储上而不是仅存储在内存中。
答案 3 :(得分:1)
Gamlor的回答在你的情况下是正确的。但是,有关其他信息,请参阅问题32的GC FAQ。
Java HotSpot Server VM使用最大可能的堆大小(由-Xmx选项设置)来计算剩余的可用空间。
Java HotSpot Client VM使用当前堆大小来计算可用空间。
这意味着服务器VM的一般趋势是扩展堆而不是刷新软引用,因此-Xmx对软引用何时被垃圾收集产生重大影响。
答案 4 :(得分:0)
Jvm按照以下简单公式确定是否应清除软引用:
时间间隔<= free_heap * ms_per_mb
interval是最后一个gc周期时间戳与软引用的最后访问时间戳之间的持续时间。 可用堆是那时可用的堆空间。 ms_per_mb是分配给堆中每个可用MB的毫秒数。 (恒定默认值为1000毫秒)
如果以上方程式为假,则引用将被清除。
因此,即使您有很多可用内存,如果您的软引用在足够长的时间内没有被访问,它们也会被清除。
-XX:SoftRefLRUPolicyMSPerMB = jvm arg可用于调整ms_per_mb常数。