Guava 地图中的驱逐惰性
当前的地图驱逐算法相当懒惰。看起来过期的对象只有在访问数据结构时才会被驱逐。
例如,从地址到索引器的映射定义为:
ConcurrentMap<Address, Indexer> indexers = new MapMaker()
.expireAfterAccess( EXPIRATION, TimeUnit.SECONDS)
.evictionListener( new IndexEvicted())
.makeMap();
导致非常令人惊讶的模式:在该地址的索引器被逐出后,给定地址的 containsKey()
立即返回 false。
使清理过程更加实时的推荐方法是什么?即删除接近实际过期时间的对象。
更新:我想进一步澄清实时的含义。对于上面的示例,EXPIRATION 为 10 秒,我希望看到插入的对象在上次访问后 10 秒内被逐出。现在这种情况还没有发生——必须以某种方式使用地图来开始驱逐。如果地图完全未使用,该物体可能会在那里停留数年。
Current eviction algorithm for maps is quite lazy. It looks like expired objects are evicted only when the data structure is accessed.
For example, the map from addresses to indexers defined as:
ConcurrentMap<Address, Indexer> indexers = new MapMaker()
.expireAfterAccess( EXPIRATION, TimeUnit.SECONDS)
.evictionListener( new IndexEvicted())
.makeMap();
leads to quite surprising pattern: while containsKey()
for the given address returns false, immediately after that indexer for that address is evicted.
What would be the recommended approach to make the clean up process more real-time? I.e. to remove the objects close to the actual expiration time.
Update: I'd like to more clarify what I mean by real-time. For the example above, EXPIRATION being 10 seconds, I'd like to see the inserted object evicted in 10 seconds after last access. That is not happening now - the map must be used somehow to start the eviction. If the map is completely unused, the object can stay there for years.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
为了及时驱逐,Guava 需要实现某种后台线程或定时重复任务。这样做会使映射变得更重,并且更难以在 J2EE 等环境或安全策略阻止随意生成线程的环境中使用。
如果您关心及时驱逐,请设置您自己的接触地图的定时线程。
另一方面,我确实同意让垃圾收集器触发驱逐会很好......例如通过使用 SoftReference 和终结器。 (是的,我知道终结器大多是邪恶的,我只是建议一种可选的最后手段策略。)
In order to have timely eviction, Guava would need to implement some sort of background thread or a timed recurring task. Doing so would make the map more heavy weight and harder to use in environments like J2EE or environments where the security policy prevents threads from being spawned willy-nilly.
If you care about timely eviction, set up your own timed thread that touches the map.
On the flip side, I do agree that having a garbage-collector triggered eviction would be nice... for example by using a SoftReference and a finalizer. (Yes, I know finalizers are mostly evil, I am simply suggesting an optional last-resort strategy.)
除了
expireAfterAccess
之外,还有一个expireAfterWrite
方法。这可能符合要求。来自 javadoc:
注意:
expireAfterAccess
和expireAfterWrite
都是“实时”的,只是一个根据上次写入时间使元素过期,另一个根据上次访问时间使元素过期。There is an
expireAfterWrite
method in addition toexpireAfterAccess
. That probably fits the bill.From javadoc:
Note: both
expireAfterAccess
andexpireAfterWrite
are "real-time", it's just that one expires elements based on their last write time, the other is based on their last access time.虽然 Dilum 的答案最有意义,但还要注意,通过自动逐出来接触数据结构不一定会逐出所有过期的条目。大多数到期发生在相对较小的批次中,因此,如果您有大量同时到期的情况,您可能必须多次接触数据结构。不幸的是,我认为没有一种简单的编程方法可以可靠地做到这一点。
While Dilum's answer makes the most sense, also note that touching a data structure with automatic eviction will not necessarily evict all expired entries. Most expiry happens in relatively small batches and therefore, if you have a large number of simultaneous expirations, you might have to touch the data structure a number of times. Unfortunately, I don't think there there is an easy programmatic way to do this reliably.