SoftReference 过早收集垃圾
我正在为我的 Android 应用程序实现缓存机制。
我使用 SoftReference
,就像我发现的许多示例一样。问题是,当我在 ListView
中向上或向下滚动时,大部分图像已经被清除。我可以在 LogCat 中看到,每次应用程序加载新图像时,我的应用程序都会被垃圾收集。这意味着 ListView
中的大部分不可见图像都消失了。
因此,每次我向后滚动到较早的位置(我之前确实下载过图像的位置),我都必须再次下载图像 - 它们没有缓存< /em>.
我也研究过这个话题。 根据本文中的 Mark Murphy 的说法,SoftReference
似乎存在(或曾经?)一个错误。其他一些结果表明同样的事情(或相同的结果); SoftReference
被清除得太早了。
有可行的解决方案吗?
I'm on my way with implementing a caching mechanism for my Android application.
I use SoftReference
, like many examples I've found. The problem is, when I scroll up or down in my ListView
, the most of the images are already cleared. I can see in LogCat that my application is garbage collected everytime the application loads new images. That means that the most of the non-visible images in the ListView
are gone.
So, everytime I scroll back to an earlier position (where I really downloaded images before) I have to download the images once again - they're not cached.
I've also researched this topic. According to Mark Murphy in this article, it seems that there is (or was?) a bug with the SoftReference
. Some other results indicates the same thing (or the same result); SoftReference
s are getting cleared too early.
Is there any working solution?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
SoftReference 是穷人的缓存。 JVM 可以使这些引用保持更长时间,但不是必须的。一旦不再存在硬引用,JVM 就会对软引用对象进行垃圾回收。您所遇到的 JVM 的行为是正确的,因为 JVM 不必将此类对象保留更长时间。当然,大多数 JVM 都会在某种程度上尝试使软引用对象保持活动状态。
因此,软引用是一种危险的缓存。如果您确实想确保缓存行为,则需要一个真正的缓存。就像 LRU 缓存。特别是如果您的缓存对性能至关重要,则应该使用适当的缓存。
SoftReference are the poor mans Cache. The JVM can hold those reference alive longer, but doesn't have to. As soon as there's no hard reference anymore, the JVM can garbage collect a the soft-referenced Object. The behavior of the JVM you're experiencing is correct, since the JVM doesn't have to hold such object longer around. Of course most JVMs try to keep the soft reference object alive to some degree.
Therefore SoftReferences are kind of a dangerous cache. If you really want to ensure a caching-behavior, you need a real cache. Like a LRU-cache. Especially if you're caching is performance-critical, you should use a proper cache.
来自 Android 培训网站:
http://developer.android.com/training/displaying-bitmaps/cache -位图.html
链接中的更多信息。
我们应该使用 LruCache 代替。
From Android Training site:
http://developer.android.com/training/displaying-bitmaps/cache-bitmap.html
More information in link.
We shoud use LruCache instead.
将每个图像缓存在持久存储中,而不仅仅是内存中。
Cache each image on persistent storage instead of just in memory.
Gamlor 的答案在您的情况下是正确的。不过,有关其他信息,请参阅 GC 常见问题解答,问题32.
Gamlor's answer is correct in your situtation. However, for additional information, see the GC FAQ, question 32.
Jvm遵循这个简单的等式来确定是否应该清除软引用:
interval <= free_heap * ms_per_mb
间隔是上次GC周期时间戳和软引用的上次访问时间戳之间的持续时间。
空闲堆是当时可用的堆空间。
ms_per_mb 是分配给堆中每个可用 MB 的毫秒数。 (恒定默认值 1000 毫秒)
如果以上方程为假,则参考值被清除。
因此,即使您有大量可用内存,如果您的软引用在足够长的时间内没有被访问,它们也会被清除。
-XX:SoftRefLRUPolicyMSPerMB= jvm arg 可用于调整 ms_per_mb 常量。
Jvm follows this simple equation to determine if a soft reference should get cleared:
interval <= free_heap * ms_per_mb
interval is duration between last gc cycle timestamp and the last access timestamp of soft reference.
free heap is heap space available at that moment.
ms_per_mb is milliseconds allocated to every MB available in heap. (Constant default 1000 ms)
If above equation is false, reference gets cleared.
So, even if you have a lot of free memory, if your soft references have not been accessed for an ample amount of time, they will get cleared.
-XX:SoftRefLRUPolicyMSPerMB= jvm arg can be used to tweak ms_per_mb constant.