文章目录
什么是 WeakReference
WeakReference 是弱引用。GC 时,JVM 可以随时回收。WeakReference 可以获取对象本身(虚引用不可以获取对象本身)也可以跟踪对象 GC。
Weak reference objects, which do not prevent their referents from being made finalizable, finalized, and then reclaimed. Weak references are most often used to implement canonicalizing mappings.
Suppose that the garbage collector determines at a certain point in time that an object is weakly reachable. At that time it will atomically clear all weak references to that object and all weak references to any other weakly-reachable objects from which that object is reachable through a chain of strong and soft references. At the same time it will declare all of the formerly weakly-reachable objects to be finalizable. At the same time or at some later time it will enqueue those newly-cleared weak references that are registered with reference queues.
弱引用对象,它不阻止它们的引用对象被设定为 finalizable、finalized,然后被回收。弱引用最常用于实现规范化映射。
假设垃圾收集器在某个时间点确定一个对象是弱可达的。此时,它将自动清除对该对象的所有弱引用,以及对任何其他弱可达对象的所有弱引用,而该对象可通过强和软引用链访问。同时,它将声明所有以前弱可达的对象为 finalizable。在同一时间或稍后的时间,它将对那些新清除的已注册到引用队列中的弱引用进行排队。
public class WeakReference<T> extends Reference<T> {
public WeakReference(T referent) {
super(referent);
}
public WeakReference(T referent, ReferenceQueue<? super T> q) {
super(referent, q);
}
}
ReferenceQueue
ReferenceQueue 一般会和 WeakReference 配合使用。举个例子,当对象 obj 被回收以后,WeakReference 对象会被放入 ReferenceQueue 中:
import java.lang.ref.ReferenceQueue;
import java.lang.ref.WeakReference;
public class Test1 {
public static void main(String[] args) {
Object obj = new Object();
WeakReference reference = new WeakReference(obj, new ReferenceQueue());
}
}
WeakHashMap 中就是类型为 Object 的 K 被回收后,会将 Entry 对象放入 ReferenceQueue 中。
WeakHashMap
- Entry 继承自 WeakReference
- WeakHashMap 中声明了全局 ReferenceQueue
- Entry 的 Value 作为 Key 的伴随数据。伴随的 key 而生,伴随 key 而死。
- 当 Entry 的 key 被 GC 时,该 Entry 会被放入 ReferenceQueue 中。下一次 put 或 get 时,Entry 从 ReferenceQueue 出队,然后根据 Entry 的 hash 值计算其在 table 中的位置,并移除。
Entry 继承自 WeakReference
private static class Entry<K,V> extends WeakReference<Object> implements Map.Entry<K,V> {
V value;
final int hash;
Entry<K,V> next;
/**
* Creates new entry.
* 构造方法
*/
Entry(Object key, V value,
ReferenceQueue<Object> queue,
int hash, Entry<K,V> next) {
super(key, queue);
this.value = value;
this.hash = hash;
this.next = next;
}
}
WeakHashMap 中声明了全局 ReferenceQueue
/**
* Reference queue for cleared WeakEntries
* Reference queue 用于保存已经 key 已经被回收了的 Entry
*/
private final ReferenceQueue<Object> queue = new ReferenceQueue<>();
put 和 get 时回收 WeakEntries
put 和 get 方法都会调用 expungeStaleEntries 方法来删除 table 中 key 已经被回收的 Entry。
put
public V put(K key, V value) {
Object k = maskNull(key);
int h = hash(k);
Entry<K,V>[] tab = getTable(); // 内部调用 expungeStaleEntries
int i = indexFor(h, tab.length);
for (Entry<K,V> e = tab[i]; e != null; e = e.next) {
if (h == e.hash && eq(k, e.get())) {
V oldValue = e.value;
if (value != oldValue)
e.value = value;
return oldValue;
}
}
modCount++;
Entry<K,V> e = tab[i];
tab[i] = new Entry<>(k, value, queue, h, e);
if (++size >= threshold)
resize(tab.length * 2);
return null;
}
get
public V get(Object key) {
Object k = maskNull(key);
int h = hash(k);
Entry<K,V>[] tab = getTable(); // 内部调用 expungeStaleEntries
int index = indexFor(h, tab.length);
Entry<K,V> e = tab[index];
while (e != null) {
if (e.hash == h && eq(k, e.get()))
return e.value;
e = e.next;
}
return null;
}
getTable
/**
* Returns the table after first expunging stale entries.
* 在第一次删除过期 entries 后返回 table。
*/
private Entry<K,V>[] getTable() {
expungeStaleEntries();
return table;
}
expungeStaleEntries
/**
* Expunges stale entries from the table.
* 从 table 中删除过期的 entries
*/
private void expungeStaleEntries() {
for (Object x; (x = queue.poll()) != null; ) {
synchronized (queue) {
@SuppressWarnings("unchecked")
Entry<K,V> e = (Entry<K,V>) x; // 将 x 强转为 Entry e
int i = indexFor(e.hash, table.length); // e 在 table 中的下标
// prev 和 p 的初始值都是 prev
Entry<K,V> prev = table[i];
Entry<K,V> p = prev;
while (p != null) {
Entry<K,V> next = p.next;
if (p == e) { // 找到 e 了,从 table 中删除之
if (prev == e)
table[i] = next;
else
prev.next = next;
// Must not null out e.next;
// stale entries may be in use by a HashIterator
// 过期的 entries 可能正在被 HashIterator 使用,所以 e.next 不能设置为 null
e.value = null; // Help GC
size--;
break;
}
prev = p;
p = next;
}
}
}
}