弱引用
日常在编码的时候开发者一般不会考虑垃圾回收,因为JVM会自动进行GC,这也是JVM中GC的本质
当在使用缓存的场景下,缓存中的对象会跟程序拥有一样的生命周期,使得对象无法被GC,当缓存中的对象过时无法及时GC,并且缓存占用内存会越来越大,造成资源浪费,甚至造成内存溢出。
以上所讲均是在strong reference 指向对象的情况之下,为了解决上述问题,JVM具有了弱引用的性能
弱引用指的是指向对象的引用为weak reference,当jvm gc时,如果一个对象仅被弱引用指向,则这个对象一定会被回收。
从jdk代码层面进行理解,以WeakHashMap和ThreadLocal为例分析
WeakHashMap
WeakHashMap与HashMap类似,是一个基于数组+单链表结构的哈希表
但是WeakHashMap中的Entry是弱引用的,会在GC时回收,常用来做缓存。
属性
//存储即将被GC的对象引用
private final ReferenceQueue<Object> queue = new ReferenceQueue<>();
Entry
Entry是一个单链表结构
private static class Entry<K,V> extends WeakReference<Object> implements Map.Entry<K,V> {
V value;
final int hash;
Entry<K,V> next;
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;
}
......
}
Entry继承了WeakReference,所以Entry的对象是一个弱引用对象
Entry中并没有存储Key值,是由于Key值存储在Reference的referent对象中,此Key会在GC时使用到。
存储数据
public V put(K key, V value) {
......
//创建Entry
tab[i] = new Entry<>(k, value, queue, h, e);
if (++size >= threshold)
resize(tab.length * 2);
return null;
}
创建Entry会调用Reference的构造方法
Reference(T referent, ReferenceQueue<? super T> queue) {
this.referent = referent; //key值
this.queue = (queue == null) ? ReferenceQueue.NULL : queue;
}
删除不可用的条目
在get/put等方法时,要先判断是否进行了GC,即需要删除不可用的已经被GC的数据
private Entry<K,V>[] getTable() {
expungeStaleEntries();
return table;
}
key为弱引用,被GC
当key被GC时,使得value置为null,被GC
删除不可用的条目
private void expungeStaleEntries() {
for (Object x; (x = queue.poll()) != null; ) {
synchronized (queue) {
@SuppressWarnings("unchecked")
Entry<K,V> e = (Entry<K,V>) x;//要删除的对象
int i = indexFor(e.hash, table.length);//获取对象的下标
Entry<K,V> prev = table[i];//获取entry
Entry<K,V> p = prev;
while (p != null) {
Entry<K,V> next = p.next;//下一个节点
if (p == e) {
if (prev == e)
table[i] = next;//数据覆盖,删除要回收的entry
else
prev.next = next;
// Must not null out e.next;
// stale entries may be in use by a HashIterator
e.value = null; //
size--;
break;
}
prev = p;
p = next;
}
}
}
}
当key被GC时,会将引用对象的引用存储到ReferenceQueue队列中,然后遍历ReferenceQueue队列删除不可用的条目,并将value置为null
总结
WeakHashMap工作原理
WeakHashMap是一个基于数组+单链表结构的哈希表,类似于HashMap,不过WeakHashMap中的Entry节点继承了WeakReference,是弱引用的,即当JVM GC时,会将WeakHashMap中的数据进行回收,MaWeakHashMap适合做缓存。
如何进行回收
Reference是一个抽象类,里面有一个ReferenceQueue队列,此队列是链表结构,存储了即将要被GC的引用对象,WeakHashMap在存储或者查找数据时,需要遍历的此ReferenceQueue队列,删除不可用的数据