什么是WeakHashMap,何时使用它?

159

WeakHashMap 是什么?何时应该使用它?WeakHashMapHashMap 之间有什么区别?


2
什么是WeakHashMap? - developer
其他问题的标题包含了你的第二个问题。同时,关于什么是WeakHashMap的答案基本上解释了它和普通HashMap之间的区别。重复相同的问题并不会使它成为一个新问题。 - Péter Török
8个回答

87

如果没有其他对键对象的强引用,弱哈希映射中的元素可以被垃圾回收器回收,这使它们非常适用于缓存/查找存储。

弱引用不仅限于这些哈希表,您还可以使用WeakReference来处理单个对象。它们有助于节省资源,您可以保持对某个东西的引用,但在没有其他引用时允许其被回收(顺便说一下,强引用是正常的Java引用)。还有一种弱引用,通常不像软引用那样容易被收集(当最后一个强引用消失后,软引用往往不会持续太久)。


23
根据这篇文章 链接,WeakHashMap 不适合用于缓存,因为它依赖于对键的强引用,而不是存储在映射中的值。 - Ivaylo Slavov
3
关键在于它不是一个强引用。我不明白这为什么是个问题。如果关键对象消失,任何相关的缓存数据都将被删除,听起来像是一个缓存/查找存储。如果您希望值本身可以被回收,请通过WeakReference将其存储在映射中,但在这种情况下您可以使用普通映射。 - vickirk
8
如果缓存的数据与对象有逻辑关联,我同意这种方式。但是我不会用“经典缓存”来称呼WeakHashMap缓存,因为在我的看法中,缓存应该根据值或特定过期策略而不是键来删除数据。 - Ivaylo Slavov
1
缓存就是缓存,无论它是保证持久的,还是你必须执行 {if !exists(key) recreateRecord(key)}。 - Blessed Geek
2
Ivaylo提供的链接现已失效。 - Phil Hamer
显示剩余3条评论

52

正如其他人已经指出的那样,弱引用提供了一种使用对象作为键而不创建对它的强引用的方法。这在你不想削弱JVM垃圾回收能力却仍然需要追踪对象某方面的情况下非常有用,因此弱引用非常适合用于缓存或存储关于对象的元数据。

我建议阅读 Oracle 博客文章《理解弱引用》,其中介绍了 Java 中的强引用与弱引用的区别。如果没有理解这个区别,该数据结构本身就毫无意义。


5
这是原文中的一句好句子:Weak references使您能够利用垃圾回收器来确定对象是否可达,从而避免自己进行判断。 - Christophe Roussy
1
很遗憾,该链接已经失效,降低了这个答案的实用性。 - Richard Rast
实际上,只有在您无法对所涉及的类进行子类化时,这才有意义。否则,您可以通过组合进行子类化以处理“元数据”,并完全避免使用弱引用的需要。 - Pacerier
3
注意:@RichardRast 和 Sudhir Krishnan - 我已修复问题中的链接。现在链接确实可以使用。 - DSlomer64
@DSlomer64 很遗憾,链接又挂了。真讽刺,关于弱引用的帖子的链接本身就是一个弱引用! - Kathir
显示剩余2条评论

24

请查看Effective Java第二版26页。

另一个常见的内存泄漏来源是缓存。一旦您将对象引用放入缓存中,很容易忘记它在那里,并在其变得无关紧要之后长时间将其留在缓存中。有几种解决方案可解决这个问题。如果您足够幸运实现了一个缓存,其中条目仅在缓存外部对其键具有引用时才相关,请将缓存表示为WeakHashMap; 条目将在过时后自动删除。请记住,WeakHashMap仅在所需的缓存条目的寿命由键的外部引用(而不是值)确定时才有用。


2
SoftHashMap是一个正确的选择。 - Pacerier

12

来自jGuru:

WeakHashMap是一种特殊的Map实现,其中map的键存储在java.lang.ref.WeakReference中。通过将键存储在弱引用中,当仅从弱引用引用到键时,键-值对可以动态地从map中丢弃。这使得WeakHashMap成为一个弱引用列表的优秀实现,在该列表中,未在其他地方使用的条目可能会被删除且没有副作用。另外,仅因为可以删除键,并不意味着它会立即被删除。如果系统有足够的资源,则未在外部引用的弱键引用可能会保留很长时间。

更多关于引用(References)


11
弱引用是关于可达性和让垃圾回收器(GC)为你工作。我认为最好理解弱引用试图解决的问题并看到它的实际应用:
  • 一篇关于IBM文章的内容:

    Java理论与实践:使用弱引用修复内存泄漏。 全局映射的内存泄漏,识别内存泄漏,弱引用拯救,...

  • 一篇关于何时使用WeakHashMap的博客文章(链接已失效)

    ... 如果WeakHashMap不适用于缓存,那它有什么用处呢? 它适用于实现规范化映射。比如说你想将一些额外的信息与你持有强引用的对象关联起来。 你在WeakHashMap中放置一个以对象为键、额外信息为值的条目。只要你持有该对象的强引用, 就可以检查映射以检索额外信息。一旦释放对象,映射条目就会被清除,额外信息所占用的内存也会被释放。...

  • java.lang.ref的文档


4

人们使用它来实现“缓存内存”。如果您的应用程序中有一些经常重复使用的对象,并且它们的构建很昂贵,而且有太多的对象无法全部保存在内存中,那么您可以使用WeakHashMap。

将当前未使用的对象放入其中。当需要该对象时,从地图中取出。大多数情况下,这些对象将停留在地图中。诀窍在于它们不是直接持有,而是通过WeakReferences进行持有。所以,如果真的“拥挤”了,当我们的内存不足时,GC将被允许收集它们。因此,每次尝试从WeakHashMap中获取对象时,您必须确保它仍然存在。否则,您需要重新创建它。


3
您可以使用WeakHashMap来减少因缓存某些对象而导致的内存泄漏的可能性。当所有对键的引用被删除时,WeakHashMap将自动删除条目。请保留HTML标签。

2
弱引用哈希映射允许其条目被垃圾回收,而不是等待整个哈希映射未使用。因此,当键不再在普通使用中时,它会自动删除单个值。
它可用于防止内存泄漏,其中哈希映射永远不会作为一个或多个键仍在使用而被回收,即使最大值不是如用户数据等...

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接