Javadocs说:“当一个密钥被丢弃后,其条目有效从地图中删除”。
但除非有另一个线程偶尔删除这些Map.Entry
条目,否则地图不会强烈引用值对象?但是由于没有运行这样的线程,只有get
方法调用可以删除这些条目 - 一次一个。
出于这个原因,我几乎总是使用WeakHashMap<K, WeakReference<V>>
。为什么他们没有将默认行为 - 值作为弱引用?
答案 0 :(得分:9)
引用队列用于自动删除条目。
http://docs.oracle.com/javase/1.4.2/docs/api/java/lang/ref/ReferenceQueue.html
引用队列,在检测到适当的可达性更改后,垃圾收集器将附加的注册引用对象附加到该引用队列。
基本上,弱引用是垃圾收集器的核心部分,因此当GC扫描发生时,会找到未使用的引用并将其放入队列,然后可以根据这些队列的内容采取操作。
线程可以位于队列的remove
方法上,以便在需要进行清理或poll
队列时收到警报。
"Java theory and practice: Plugging memory leaks with weak references"解释说:
WeakHashMap
的实现说明了一个弱引用的常用习惯用法 - 一些内部对象扩展WeakReference
。...
WeakHashMap
使用弱引用来保存映射键,这允许在应用程序不再使用密钥对象时对其进行垃圾回收,get()
实现可以告诉实时映射。死亡的是WeakReference.get()
是否返回null
。但这只是使Map的内存消耗在应用程序的整个生命周期内不增加所需的一半;在收集关键对象后,还必须执行某些操作以从地图中删除死区条目。 否则,Map只会填充与死键相对应的条目。虽然这对应用程序是不可见的,但它仍然可能导致应用程序内存不足,因为Map.Entry和value即使密钥是,也不会收集对象。...
引用队列是垃圾回收器向应用程序反馈关于对象生命周期的信息的主要方法。弱引用有两个构造函数:一个只将引用作为参数而另一个也引用参考队列。当使用关联的引用队列创建弱引用并且引用对象成为GC的候选者时,在引用被清除之后,引用对象(不是引用对象)在引用队列上排队。然后,应用程序可以从引用队列中检索引用,并了解已经收集了引用对象,以便它可以执行相关的清理活动,例如,清除已经从弱集合中删除的对象的条目。 (引用队列提供与BlockingQueue相同的出列模式 - 轮询,定时阻塞和不定时阻塞。)
编辑:
即使有队列,弱地图仍然可以泄漏。 Ephemerons试图解决弱键引用引用键的强保持值的情况。它们不能在java中实现。
Ephemerons解决了在尝试使用注册表将属性“附加”到对象时常见的问题。当某个属性应附加到某个对象时,该属性应该(就GC行为而言)通常具有该对象的实例变量所具有的生命周期。但是,通过在对象及其属性之间建立外部关联(例如:
),这很复杂property --------- registry --------- association --------- object
这里,注册表(第三方)将保留关联本身,这需要从注册表手动删除(而不是自动垃圾收集)。虽然通过使用各种弱关联类型之一可以在任何给定的具体情况下解决这个问题,但选择“正确”的关联类型取决于多种因素,其中一些因素可以动态变化。
Ephemerons通过定义ephemeron的'contents'(值)将被强烈保持直到已知密钥被垃圾收集来解决这个问题。从那时起,ephemeron的内容将被弱化。因此,当且仅当密钥是垃圾收集时,ephemeron的内容才有资格进行垃圾收集,这是我们为对象的实例变量观察到的确切行为。