Java Reference源码分析

Reference是个抽象类,它实现了所有reference对象的通用操作。这个类主要跟垃圾收集器密切相关。

1.Reference内部四种状态
  1. Active:Reference对象被垃圾收集器特殊对待。当垃圾收集器探测到引用可达性后,它将改变reference对象到pending状态或者inactive状态。如果refence对象在创建的时候包含一个queue时,它将改变对象的状态到pending。如果没有queue,它直接将对象改变到inactive状态。新创建的reference对象是active状态。
  2. Pending: 一个refer对象在pending-reference集合中,等待reference线程处理器加入到队列中。如果对象在创建的时候没有注入队列,则引用对象不会有此状态。
  3. Enqueued:当一个refer对象加入到队列后,就变为enqueued状态。
  4. Inactive:不能发生任何状态的转化

总结:当垃圾收集回收引用对象时,如果对象在创建的时候注入了队列,则把回收的对象加入到队列。加入队列的目的是为了程序员手动删除被垃圾回收的对象。为什么还要手动删除被回收的引用对象了?我们看一下WeakHashMap的源码实现

  /**
     * The entries in this hash table extend WeakReference, using its main ref
     * field as the key.
     */
    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;
        }

从上面的源码中可以看出,在创建Entry的时候注入了ReferenceQueue队列。由于Entry继承了WeakReference,但是并没有包装成WeakReference。
那么为什么不把Entry直接包装成WeakReference? 原因很简单,加入把Entry包装成WeakReference,就不能使用Hash的功能,依据Key定位value。

通过在Entry的构造函数中调用super(key)。把key包装成WeakReference对象,当垃圾收集器判定到只有引用可达性时,就把key设置为null。程序员通过迭代queue中的元素,把table中的key为null的元素删除

2. Reference内部的实例字段及类字段
     /* 被GC处理 */
    private T referent;
    //引用队列
    volatile ReferenceQueue<? super T> queue;

    /* When active:   NULL
     *     pending:   this
     *    Enqueued:   next reference in queue (or this if last)
     *    Inactive:   this
     */
    @SuppressWarnings("rawtypes")
    Reference next;

    /* active状态:是discovered 引用集合中下一个元素通过GC维护
     * pending: 是pending list 中的下一个元素
     * otherwise:   NULL
     */
    //被vm使用
    transient private Reference<T> discovered;  /* used by VM */
     /*等待进入队列的集合列表。垃圾收集器添加引用到这个集合,等待Reference-Handler线程移除它们。
     *此字段是个类常量。所有的实例对象都有一个pending.
     */
    private static Reference<Object> pending = null;
3. 上面源码中queue与next字段的关系
  • Active:queue = ReferenceQueue当queue被注册时。或者queue=ReferenceQueue.NULL。next = null;表示此引用处于Active状态
  • Pending:queue=ReferenceQueue当queue被注册时。next=this。next=this表示此引用处于Pending状态。
  • Enqueued: queue = ReferenceQueue.ENQUEUED;next=队列的下一个实例。或者如过是队列的尾部,则是队列本身。
  • Inactive: queue = ReferenceQueue.NULL; next = this.
添加pending引用元素到queue源码分析

当一个引用的队列不为空时,在进行垃圾回收的时候把状态转化为pending状态。
经过前面的介绍,当状态转变为pending状态时,discovered中保存的是pending list中的下一个元素。
把r从pending list中移除。加入到queue
pending = r.discovered;
r.discovered = null;

   static boolean tryHandlePending(boolean waitForNotify) {
        Reference<Object> r;
        Cleaner c;
        try {
            synchronized (lock) {
                if (pending != null) {
                    r = pending;
                    // 'instanceof' might throw OutOfMemoryError sometimes
                    // so do this before un-linking 'r' from the 'pending' chain...
                    c = r instanceof Cleaner ? (Cleaner) r : null;
                    // unlink 'r' from 'pending' chain
                    pending = r.discovered;
                    r.discovered = null;
                } else {
                    // The waiting on the lock may cause an OutOfMemoryError
                    // because it may try to allocate exception objects.
                    if (waitForNotify) {
                        lock.wait();
                    }
                    // retry if waited
                    return waitForNotify;
                }
            }
        } catch (OutOfMemoryError x) {
            // Give other threads CPU time so they hopefully drop some live references
            // and GC reclaims some space.
            // Also prevent CPU intensive spinning in case 'r instanceof Cleaner' above
            // persistently throws OOME for some time...
            Thread.yield();
            // retry
            return true;
        } catch (InterruptedException x) {
            // retry
            return true;
        }

        // Fast path for cleaners
        if (c != null) {
            c.clean();
            return true;
        }

        ReferenceQueue<? super Object> q = r.queue;
        if (q != ReferenceQueue.NULL) q.enqueue(r);
        return true;
    }
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值