WeakHashMap和强引用值

Javadocs说:“当一个密钥被丢弃时,它的条目将被有效地从地图中删除”。

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

因为这个原因WeakHashMap<K, WeakReference>我几乎总是使用WeakHashMap<K, WeakReference> 。 为什么他们没有将默认行为 – 值作为弱引用呢?

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

http://docs.oracle.com/javase/1.4.2/docs/api/java/lang/ref/ReferenceQueue.html

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

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

线程可以位于队列的remove方法上,以便在需要进行清理或poll队列时收到警报。

“Java理论与实践:用弱引用来堵塞内存泄漏”解释说:

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的内容才有资格进行垃圾收集,这是我们为对象的实例变量观察到的确切行为。