Reference ReferenceQueue WeakHashMap详解

强引用
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;
                }
            }
        }
    }
}

你可能感兴趣的:(java,jvm)