Java Reference源码分析
来源:互联网 发布:域名污染查询 编辑:程序博客网 时间:2024/05/29 08:47
Reference是个抽象类,它实现了所有reference对象的通用操作。这个类主要跟垃圾收集器密切相关。
Reference内部四种状态
- Active:Reference对象被垃圾收集器特殊对待。当垃圾收集器探测到引用可达性后,它将改变reference对象到pending状态或者iactive状态。如果refence对象在创建的时候包含一个queue时,它将改变对象的状态到pending。如果没有queue,它直接将对象改变到iactive状态。新创建的reference对象是active状态。
- Pending: 一个refer对象在pending-reference集合中,等待reference线程处理器加入到队列中。如果对象在创建的时候没有注入队列,则引用对象不会有此状态。
- Enqueued:当一个refer对象加入到队列后,就变为enqueued状态。
- 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的元素删除。
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;
上面源码中queue与next字段的关系
- Active:queue = ReferenceQueue当queue被注册时。或者queue=ReferenceQueue.NULL。next = null;
- Pending:queue=ReferenceQueue当queue被注册时。next=this
- 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 0
- Java Reference 源码分析
- Java Reference源码分析
- 《Java源码分析》:ReferenceQueue、Reference及其子类
- 《Java源码分析》:ReferenceQueue、Reference及其子类
- 《Java源码分析》:ReferenceQueue、Reference及其子类
- JDK源码 Java Reference
- java源代码 Reference和ReferenceQueue分析
- java.lang.ref.Reference源代码分析
- Java源码分析:Iterator
- Java Thread源码分析
- java Thread 源码分析
- Java HashMap 源码分析
- 深入JAVA源码分析
- java HashMap源码分析
- Java LinkedLIst 源码分析
- java BufferdInputStream源码分析
- java Thread源码分析
- java ReentrantLock源码分析
- mysql之事务详解
- 校验下载的CentOS镜像是否完整
- Java经典算法40例(十七)
- mysql中case when用法与及注意事项
- 黑马商城项目(三)之二
- Java Reference源码分析
- Java经典算法40例(十八)
- Easyui Datagrid 根据参数设定样式
- 使用 IntelliJ IDEA写出你的第一个mapruduce应用
- 如何找出单链表中的倒数第k个元素
- 12备份和恢复数据库
- 按值传递和按引用传递的区别
- POJ 3177 Redundant Paths 笔记
- day_06C语言基础