弱引用分析

弱引用

日常在编码的时候开发者一般不会考虑垃圾回收,因为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队列,删除不可用的数据

ThreadLocal

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值