我最近发现了Java中的WeakHashMap
数据结构。
但是,我不明白它的意思是垃圾收集不再正常使用时的映射。数据结构如何知道我将不再使用我的程序中的密钥?如果我长时间没有提到钥匙怎么办?
答案 0 :(得分:17)
但是,我不明白它的意思是垃圾收集不再正常使用时的映射。
行。在正常情况下,当垃圾收集器运行时,它将删除程序无法再使用的对象。技术术语是“无法访问的对象”,这意味着程序执行无法再获取对象的引用。无法访问的对象可能在下一个GC循环中收集......或不。无论哪种方式,它都不再是应用程序的关注点。
在这种情况下,WeakHashMap
使用名为WeakReference
的特殊类来引用键。弱引用是一种对象,其行为类似于间接指针(指向持有指针的对象的指针)。它有一个有趣的特性,垃圾收集器可以打破引用;即用null
替换它包含的引用。并且规则是当GC注意到通过正常(强)或软引用链 1 的弱引用 >
短语“不再正常使用”实际上意味着关键对象不再强烈或轻柔地可达;即通过强大的和/或软的参考链。
数据结构如何知道我将不再使用我的程序中的密钥?
WeakHashmap
没有这样做。相反,它是GC注意到密钥不是很强的可达。
作为正常遍历的一部分,GC将查找并标记所有可强制到达的对象。然后它遍历所有WeakReference
个对象并检查是否
他们引用的对象已被标记,如果没有,则将其打破。 (或者类似的东西......我从来没有看过实际的GC实现。而且它也必须处理SoftReference
和PhantomReference
对象,这很复杂。)
WeakHashmap
唯一涉及的是:
WeakReference
个对象作为键,WeakReferences
的哈希表条目。如果我长时间没有提到钥匙怎么办?
决定弱引用应该被打破的标准不是基于时间的。
但是时序可能会影响是否删除了某个键。例如,密钥可以1)不再是强引用,2)从地图中检索,3)被分配给可到达的变量,使其再次被强烈引用。如果GC在密钥不可达的窗口期间未运行,则密钥及其关联值将保留在映射中。 (这是你想要发生的......)
1 - 软引用是一种在堆内存不足时允许GC中断的引用。
答案 1 :(得分:4)
Java有一个 references 系统,该语言可以告诉您的代码某个对象是否仍在使用中。您可以使用引用来检测某个对象何时被特别标识为不再使用或可用,然后可以相应地执行操作。如果您对如何使用它们感到好奇,This tutorial会深入介绍参考文献。
在内部,WeakHashMap
可能会使用这些引用来自动检测何时无法再使用给定的密钥。然后,实现可以从哈希表中删除这些对象,以便它们不再占用任何空间。
希望这有帮助!
答案 2 :(得分:3)
JVM垃圾按以下顺序收集:
WeakReference
SoftReference
通常,垃圾收集器只有垃圾收集未引用的对象。
就垃圾收集器而言,对对象的弱引用不算作引用。垃圾收集器可能会或可能不会收集它们。通常,除非内存不足,否则它不会收集它们,但是没有保证。
如果JVM的内存不足,垃圾收集器将收集软引用的对象。在任何软引用对象被垃圾收集之前,所有弱引用对象都将被垃圾收集。
来自SoftReference的javadoc:
在虚拟机抛出
之前,保证已清除对软可访问对象的所有软引用OutOfMemoryError
答案 3 :(得分:2)
我把你的问题看作是询问“常规使用”的具体措辞,所以假设你已经知道强弱参考。常规使用是指弱hashmap包含也被某些其他数据结构(强烈地)引用的键的情况。对密钥的至少一个强引用的存在是“常规使用”。只要此其他数据结构引用密钥,就不能对密钥进行垃圾回收。当其他数据结构不再可访问(指向它的指针不再存在)时,该密钥也变得无法访问。它不再是常规使用,因为它的唯一引用是映射中的弱点。垃圾收集器最终可以回收它,映射消失。
如果你想通过子类扩展类型C但是不能:当C是具有许多实现的接口时,就会出现这种情况。您可以通过使用键类型为C的弱哈希映射以及要在新类E中包含的新字段来解决此问题。无论何时创建C实例,还要创建一个E实例并将该对添加到映射中,然后用于在C intance的生命周期内访问新字段。当C实例变为垃圾时,映射和E实例也会变为垃圾。这是自动的,因为hashmap很弱。如果不是,则必须手动清理它,就像你必须以没有垃圾收集器的语言显式释放存储一样。