Java的WeakHashMap和缓存:为什么它引用键,而不是值?

2022-08-31 13:46:43

Java的WeakHashMap经常被引用为对缓存有用。不过,它的弱引用是根据地图的键而不是其值来定义的,这似乎很奇怪。我的意思是,这是我想要缓存的值,一旦除了缓存之外没有其他人强烈引用它们,我想得到垃圾回收,不是吗?

以何种方式有助于保持对键的弱引用?如果你做一个,那么我希望缓存保持'o',直到调用方不再持有强引用,我根本不关心字符串对象“some_key”。ExpensiveObject o = weakHashMap.get("some_key")

我错过了什么吗?


答案 1

WeakHashMap作为缓存没有用,至少大多数人认为它的方式是这样。正如你所说,它使用弱,而不是弱,所以它不是为大多数人想要使用它而设计的(事实上,我看到人们错误地使用它)。

WeakHashMap主要用于保存有关您无法控制其生命周期的对象的元数据。例如,如果您有一堆对象通过您的类,并且您希望跟踪有关它们的额外数据,而无需在它们超出范围时收到通知,并且不需要引用它们来保持它们处于活动状态。

一个简单的例子(也是我以前用过的一个)可能是这样的:

WeakHashMap<Thread, SomeMetaData>

您可以跟踪系统中各种线程正在执行的操作;当线程死亡时,该条目将从映射中以静默方式删除,并且如果您是对 Thread 的最后一个引用,则不会阻止该线程被垃圾回收。然后,您可以循环访问该映射中的条目,以找出有关系统中活动线程的元数据。

有关详细信息,请参阅 WeakHashMap in not a cache!

对于您所追求的缓存类型,请使用专用缓存系统(例如EHCache)或查看GuavaMapMaker类;类似的东西

new MapMaker().weakValues().makeMap();

会做你所追求的,或者如果你想变得花哨,你可以添加定时到期:

new MapMaker().weakValues().expiration(5, TimeUnit.MINUTES).makeMap();

答案 2

的主要用途是当您有映射时,当它们的键消失时,您希望消失。缓存则相反---您有映射,当它们的值消失时,您希望它们消失。WeakHashMap

对于缓存,您需要的是 .当内存紧张时,软引用将被垃圾回收。(将此与 a 进行对比,一旦不再硬引用其引用,就可以清除该引用。您希望引用在缓存中是软的(至少在键值映射不会过时的缓存中),因为这样,如果您以后查找它们,您的值可能仍将在缓存中。如果引用很弱,则您的值将立即被gc'd,从而破坏了缓存的目的。Map<K,SoftReference<V>>WeakReference

为方便起见,您可能希望隐藏实现中的值,以便缓存显示为类型而不是 。如果你想这样做,这个问题有关于网络上可用的实现的建议。SoftReferenceMap<K,V><K,SoftReference<V>>

另请注意,当您在 中使用值时,必须执行一些操作来手动删除已清除的键值对---否则,您的大小只会永远增长,并泄漏内存。SoftReferenceMapSoftReferencesMap