强引用
Object o = new Object();
o就是一个强引用, 强引用不会被VM GC, 即使内存不够抛出OutOfMemoryError也不会被回收
软引用
/**对象不可达之后,一直到内存不足时,才被回收*/
public class SoftReference<T> extends Reference<T> {...}
弱引用
/**对象不可达之后,gc运行就会被回收*/
public class WeakReference<T> extends Reference<T> {...}
虚引用
/**还没搞懂,构造的时候必须传一个ReferenceQueue*/
public class PhantomReference<T> extends Reference<T> {
...
public T get() {//但是PhantomReference的get方法,无论何时都返回的是null,这个接下来在看,,,多了怕记不住
return null;
}
}
还有WeakHashMap,之后再加上
Reference本身是一个链表的数据结构,有如下两个字段
private T referent;
Reference next;
Reference中 有个 静态的 pending字段
private static Reference pending = null;
vm会将不可达的Reference对象挂在pending链表上(VM实现);
Reference中还有个 ReferenceHandler 这个handler(Thread[Daemon线程]),
在一个静态快中初始化,
功能就是循环的访问pending,将pending中的不可达对象 入队(enqueue);
Reference & ReferenceQueue的关系:
Reference存在一个ReferenceQueue的引用,Reference存在一个ReferenceQueue的引用是在Reference的构造方法中初始化的,
如果没有指定,会传入一个全局默认的queue但是这个默认的queue,但是这个queue 没有实际的入队操作(见下面源码),
如果传入一个构造的queue,不可达的对象会入队(enqueue)
class ReferenceQueue<T>{
//有两个静态的ReferenceQueue
static ReferenceQueue NULL = new Null();//默认的ReferenceQueue
static ReferenceQueue ENQUEUED = new Null();
private static class Null extends ReferenceQueue {
boolean enqueue(Reference r) {//Null 的enqueue()没有实际的入队操作
return false;
}
}
boolean enqueue(Reference<? extends T> r) { /* Called only by Reference class */
synchronized (r) {
if (r.queue == ENQUEUED) return false;
synchronized (lock) {
r.queue = ENQUEUED;
r.next = (head == null) ? r : head;
head = r;
queueLength++;
if (r instanceof FinalReference) {
sun.misc.VM.addFinalRefCount(1);
}
lock.notifyAll();
return true;
}
}
}
}
public abstract class Reference<T>{
...
private T referent;//构造函数传入(具体的对象)
ReferenceQueue<? super T> queue;
/*(网上看来的):pending是由jvm来赋值的,
当Reference内部的referent对象的可达状态改变时,
jvm会将Reference对象放入pending链表*/
private static Reference pending = null; /* used by VM */
...
/*守护线程,将注册在queue上,
不可达的referent(pending Reference 链表)放入 queue中*/
private static class ReferenceHandler extends Thread{
ReferenceHandler(ThreadGroup g, String name) {
super(g, name);
}
public void run() {
for (;;) {//对pending的访问
...
}
}
static { //初始化守护线程:ReferenceHandler
ThreadGroup tg = Thread.currentThread().getThreadGroup();
for (ThreadGroup tgn = tg;
tgn != null;
tg = tgn, tgn = tg.getParent());
Thread handler = new ReferenceHandler(tg, "Reference Handler");
/* If there were a special system-only priority greater than
* MAX_PRIORITY, it would be used here
*/
handler.setPriority(Thread.MAX_PRIORITY);
handler.setDaemon(true);
handler.start();
}
/**
* Adds this reference object to the queue with which it is registered,
* if any.*/
public boolean enqueue() {
return this.queue.enqueue(this);
}
...
}
接下来是WeakHashMap
public class WeakHashMap<K,V> extends AbstractMap<K,V> implements Map<K,V> {
....
/*在WeakHashMap则在内部提供了一个非NULL的ReferenceQueue*/
/*WeakHashMap的实现也是通过ReferenceQueue这个“监听器”来实现自动删除那些引用不可达的key的*/
private final ReferenceQueue<Object> queue = new ReferenceQueue<>();
/*内部类,实体,继承WeakReference,重要的是构造方法*/
private static class Entry<K,V> extends WeakReference<Object> implements Map.Entry<K,V> {
V value;
int hash;
Entry<K,V> next;
Entry(Object key, V value,ReferenceQueue<Object> queue,
int hash, Entry<K,V> next) {
/*把key放入 WeakReference 的 private T referent;
WeakHashMap的key会被回收,但是value却不会被回收,
但是 通过调用 expungeStaleEntries(),value会被回收
源码如下*/
super(key, queue);
this.value = value;
this.hash = hash;
this.next = next;
}
....
}
/*核心的方法*/
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<K,V> p = prev;
while (p != null) {
Entry<K,V> next = p.next;
if (p == e) {
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
e.value = null; // Help GC
size--;
break;
}
prev = p;
p = next;
}
}
}
}
}