Java WeakHashMap和强引用值

Java WeakHashMap和强引用值,java,collections,weak-references,weakhashmap,Java,Collections,Weak References,Weakhashmap,Javadocs说“当一个键被丢弃时,它的条目将被有效地从映射中删除” 但是,除非有另一个线程偶尔删除这样的Map.Entryentries,否则值对象不会被映射强烈引用吗?但是由于没有这样的线程运行,只有get方法调用可以删除这样的条目——一次删除一个条目 出于这个原因,我几乎总是使用WeakHashMap。为什么他们不让默认行为值也作为弱引用呢?引用队列用于自动删除条目 引用队列,在检测到适当的可达性更改后,垃圾收集器会将已注册的引用对象附加到该队列 基本上,弱引用是垃圾收集器的核心部分,

Javadocs说“当一个键被丢弃时,它的条目将被有效地从映射中删除”

但是,除非有另一个线程偶尔删除这样的
Map.Entry
entries,否则值对象不会被映射强烈引用吗?但是由于没有这样的线程运行,只有
get
方法调用可以删除这样的条目——一次删除一个条目


出于这个原因,我几乎总是使用
WeakHashMap
。为什么他们不让默认行为值也作为弱引用呢?

引用队列用于自动删除条目

引用队列,在检测到适当的可达性更改后,垃圾收集器会将已注册的引用对象附加到该队列

基本上,弱引用是垃圾收集器的核心部分,因此当GC扫描发生时,会找到未使用的引用并将其放到队列中,然后可以根据这些队列的内容采取操作

线程可以位于队列的方法上,在需要进行清理或
轮询队列时发出警报

说明:

WeakHashMap
的实现说明了一种带有弱引用的常见习惯用法——一些内部对象扩展了
WeakReference

WeakHashMap
使用弱引用来保存映射键,这允许在应用程序不再使用键对象时对它们进行垃圾收集,
get()
实现可以通过
WeakReference.get()
是否返回
null
来区分活映射和死映射。但这仅仅是在应用程序的整个生命周期内防止Map的内存消耗增加所需的一半;在收集了密钥对象之后,还必须做一些事情来修剪映射中的死条目否则,映射将简单地用对应于死键的条目填充。虽然这对应用程序来说是不可见的,但仍可能导致应用程序内存不足,因为映射。条目和值对象将不会被收集,即使该键是空的

引用队列是垃圾回收器向应用程序反馈有关对象生命周期信息的主要方式。弱引用有两个构造函数:一个只将引用对象作为参数,另一个也使用引用队列。当使用关联的引用队列创建了弱引用,并且引用对象成为GC的候选对象时,在清除引用后,引用对象(而不是引用对象)将进入引用队列。然后,应用程序可以从引用队列中检索引用,并了解引用对象已被收集,以便可以执行相关的清理活动,例如删除从弱集合中掉出的对象的条目。(参考队列提供与BlockingQueue相同的出列模式——轮询、定时阻塞和非定时阻塞。)

编辑:

即使使用队列,弱映射仍然可能泄漏。试图解决弱密钥引用引用该密钥的强持有值的情况。它们不能在java中实现

当试图通过使用注册表将属性“附加”到对象时,蜉蝣解决了一个常见的问题。当某个属性应该附加到某个对象时,该属性(就GC行为而言)通常应该具有该对象的实例变量所具有的生命周期。但是,由于对象与其属性之间存在外部关联,这一点变得复杂,例如:

property --------- registry --------- association --------- object
在这里,注册表(第三方)将保留关联本身,这将需要手动从注册表中删除(而不是自动垃圾收集)。虽然在任何给定的具体情况下,通过使用各种弱关联类型中的一种,都可以解决这个问题,但选择“正确”的关联类型取决于各种因素,其中一些因素可以动态变化

蜉蝣通过定义蜉蝣的“内容”(值)将被强持有,直到知道密钥被垃圾收集为止,从而解决了这个问题。从那时起,蜉蝣的内容物将被微弱地保存。因此,当且仅当键是可垃圾回收的时,一个蜉蝣子的内容才有资格进行垃圾回收,这正是我们将观察到的对象实例变量的行为


这几乎是一个相同的问题。但我想知道我的断言是否正确:只有当get()发现密钥已被gc’ed时,条目才会被删除,坦白说,除非我使用WeakReferences作为值,否则这似乎没有多大价值。是的,它只是被轮询。如果你想要不同的东西,写你自己的版本。如果你需要不同的东西,使用一个库——写你自己的是非常棘手的。Guava有
MapMaker
,它可以让你配置键和值引用的强度:我认为WeakHashMap是半生不熟的,为什么他们要用expungeStaleEntries()轮询队列作为大多数方法的一部分,并且没有专门的线程进行阻塞读取?@Ustaman Sangat
WeakHashMap
轮询一个
ReferenceQueue
。忘记了引用队列调用我们自己的钩子的能力。我从您的链接中发现“WeakHashMap有一个名为expungeStaleEntries()的私有方法”这在大多数映射操作中都被调用。我想知道,在引用队列上生成一个实际上可以执行阻塞读取的线程是否是一个更好的主意。也许Guava的MapMaker就是这么做的。@UstamanSangat,我不知道MapMaker是怎么做的,但也许expungestalentries()轮询引用队列以使用地图分期清理。在实现我自己的密钥cleani之前,我会尝试使用MapMaker之类的工具