Java基础知识整理8:Java引用

使用

Java 中一共有 4 种类型的引用 :

  • Strong Reference 强引用,Java的默认引用实现,会尽可能长时间的存活于JVM中,当没有对象引用时会在GC后被回收;
  • Soft Reference 软引用,描述一些还有用但非必须的对象。在系统将要发生内存溢出异常之前,会将这些对象进行释放,直到JVM内存不足时才会被回收,如果还没有足够的内存,才会抛出溢出异常;
  • Weak Reference 弱引用,描述非必须的对象,强度比软引用更弱一些,被若引用引用的对象下次GC就会回收
  • Phantom Reference 虚引用,最弱的一种引用,一个对象是否有虚引用的存在,完全不会对其生存时间构成影响。唯一目的就是在这个对象被收集回收时受到一个系统通知。

相关的类

引用相关的类都在java.lang.ref下面,提供了引用对象类,支持在某种程度上与垃圾回收器之间的交互。程序中可以使用一个ref对象来维持对另外某一个对象的引用,

  • Reference
  • SoftReference
  • WeakReference
  • WeakHashMap
  • PhantomReference
  • ReferenceQueue
  • FinalReference
  • Finalizer

Reference类

Reference是一个抽象类,是引用对象的基类。该对象定义了所有引用对象的操作,引用对象是为了与垃圾回收器的密切合作而实现的,不能直接为此类创建子类。

  • Reference中包含一个对象T,引用该ref对象引用的对象
  • Reference有一个static的pending,GC会对其进行设置,该链表为GC设置的一个待GC,待入队列表
  • Reference有一个ReferenceQueue和next,用于维护一个列表
public abstract class Reference<T>{

    private T referent;  //ref对象引用的对象
    ReferenceQueue<? super T> queue; //见下面的分析
    Reference next; //下一个,链表
    
    transient private Reference<T> discovered;  /* used by VM */
    
    //GC用于同步的对象,在垃圾收集开始时,必须获得这个锁
    //任务获得这个锁的对象都应该尽可能快的释放,不应该在持有期间内调用用户代码
    static private class Lock { };
    private static Lock lock = new Lock();
    
    //等待入队的引用,垃圾收集器将引用添加到这个list
    //Reference-handler线程会将pending移除并重新设置
    //这个list被锁保护,dd
    //静态的,reference使用
    private static Reference pending = null;
    
    
    //构造方法
    Reference(T referent) {
        this(referent, null);
    }
    
    Reference(T referent, ReferenceQueue<? super T> queue) {
        this.referent = referent;
        this.queue = (queue == null) ? ReferenceQueue.NULL : queue;
    }
    
    //返回ref对象引用的对象
    public T get() {
        return this.referent;
    }
    
    //清除引用对象,调用该方法不会导致排队
    public void clear() {
        this.referent = null;
    }
    
    //返回该对象是否被在排队
    public boolean isEnqueued() {
        synchronized (this) {
            return (this.queue != ReferenceQueue.NULL) && (this.next != null);
        }
    }
    
    
    //将ref对象添加到注册的队列中
    //这个方法只会被java代码调用,垃圾回收器会直接将引用加入队列,无需调用此方法。 
    public boolean enqueue() {
        return this.queue.enqueue(this);
    }
    
    
}

Reference内部包含的一个ReferenceHandler线程,用来将pending引用入队列;由于该线程时static的,只会开一个

private static class ReferenceHandler extends Thread {

        ReferenceHandler(ThreadGroup g, String name) {
            super(g, name);
        }

        public void run() {
            for (;;) { //无线循环

                Reference r;
                synchronized (lock) { //需要先获取lock
                    if (pending != null) {
                        r = pending;
                        Reference rn = r.next;
                        pending = (rn == r) ? null : rn;
                        r.next = r;
                    } else {
                        try {
                            lock.wait(); //pending为null 等待
                        } catch (InterruptedException x) { }
                        continue;
                    }
                }

                // Fast path for cleaners
                if (r instanceof Cleaner) {
                    ((Cleaner)r).clean();
                    continue;
                }

                ReferenceQueue q = r.queue;
                if (q != ReferenceQueue.NULL) q.enqueue(r);
            }
        }
    }

启动引用处理线程ReferenceHandler

static {
        ThreadGroup tg = Thread.currentThread().getThreadGroup();
        for (ThreadGroup tgn = tg;
             tgn != null;
             tg = tgn, tgn = tg.getParent());
        Thread handler = new ReferenceHandler(tg, "Reference Handler");
        handler.setPriority(Thread.MAX_PRIORITY);//设置优先级为最高
        handler.setDaemon(true);//守护线程
        handler.start();//启动线程
    }

ReferenceQueue类

ReferenceQueue类内部主要维护了链表的head和长度等信息,可以将pedding添加到队列中或移除

public class ReferenceQueue<T> {
    public ReferenceQueue() { }

    private static class Null extends ReferenceQueue {
        boolean enqueue(Reference r) {
            return false;
        }
    }

    static ReferenceQueue NULL = new Null();
    static ReferenceQueue ENQUEUED = new Null();

    static private class Lock { };
    private Lock lock = new Lock();
    private volatile Reference<? extends T> head = null;
    private long queueLength = 0;
    
    boolean enqueue(Reference<? extends T> r) {
    
    private Reference<? extends T> reallyPoll() {
    public Reference<? extends T> poll() //
    public Reference<? extends T> remove(long timeout)
    public Reference<? extends T> remove()
}

SoftReference类

public class SoftReference<T> extends Reference<T> {

    
    static private long clock; //时间戳锁,GC更新

    private long timestamp; //调用get方法时更新,VM会使用该变量来清除但也不一定

    //构造函数
    public SoftReference(T referent) {
        super(referent);
        this.timestamp = clock;
    }

    //构造函数
    public SoftReference(T referent, ReferenceQueue<? super T> q) {
        super(referent, q);
        this.timestamp = clock;
    }

    //返回这个ref对象引用的对象,如果被清除了,会返回null
    public T get() {
        T o = super.get();
        if (o != null && this.timestamp != clock)
            this.timestamp = clock;
        return o;
    }

}

WeakReference类

public class WeakReference<T> extends Reference<T> {

    
    public WeakReference(T referent) {
        super(referent);
    }

    
    public WeakReference(T referent, ReferenceQueue<? super T> q) {
        super(referent, q);
    }

}

PhantomReference类

public class PhantomReference<T> extends Reference<T> {

    public T get() {
        return null;
    }

    public PhantomReference(T referent, ReferenceQueue<? super T> q) {
        super(referent, q);
    }
}

FinalReference类

class FinalReference<T> extends Reference<T> {

    public FinalReference(T referent, ReferenceQueue<? super T> q) {
        super(referent, q);
    }

}

//final的类,package级别,不能被其他类调用和继承
final class Finalizer extends FinalReference { 

    //一个本地方法,调用一个任意对象的finalize方法,只要是protected的
    static native void invokeFinalizeMethod(Object o) throws Throwable;
    //ReferenceQueue 一个队列,静态的
    static private ReferenceQueue queue = new ReferenceQueue();
    static private Finalizer unfinalized = null;
    static private Object lock = new Object();//锁

    private Finalizer next = null,prev = null; //双向链表

    //是否被调用了finalize方法
    private boolean hasBeenFinalized() { 
        return (next == this);
    }
    //获得锁,加入链表中
    private void add() {
        synchronized (lock) {
            if (unfinalized != null) {
                this.next = unfinalized;
                unfinalized.prev = this;
            }
            unfinalized = this;
        }
    }
    //获得锁,从unfinalized链表中移除
    private void remove() {
        synchronized (lock) {
            if (unfinalized == this) {
                if (this.next != null) {
                    unfinalized = this.next;
                } else {
                    unfinalized = this.prev;
                }
            }
            if (this.next != null) {
                this.next.prev = this.prev;
            }
            if (this.prev != null) {
                this.prev.next = this.next;
            }
            this.next = this;   /* Indicates that this has been finalized */
            this.prev = this;
        }
    }
    //构造方法,立即加入到队列
    private Finalizer(Object finalizee) {
        super(finalizee, queue);
        add();
    }

    //VM虚拟机调用,创建一个Finalizer对象,引用finalizee
    static void register(Object finalizee) {
        new Finalizer(finalizee);
    }
    //运行引用指向对象的析构函数
    private void runFinalizer() {
        synchronized (this) {//如果已经被析构了,则返回,只会调用一次
            if (hasBeenFinalized()) return;
            remove();//从unfinalized链表移除,解除被链引用
        }
        try {
            Object finalizee = this.get();//获取引用的对象,不为空且不为枚举则通过
            //invokeFinalizeMethod原生方法调用finalizee的finalize方法(Object中定义)
            if (finalizee != null && !(finalizee instanceof java.lang.Enum)) {
                invokeFinalizeMethod(finalizee);
                finalizee = null;//置为空
            }
        } catch (Throwable x) { }
        super.clear();//不引用了 this.referent = null;
    }

    //创建一个线程
    private static void forkSecondaryFinalizer(final Runnable proc) {
        AccessController.doPrivileged(
            new PrivilegedAction<Void>() {
                public Void run() {
                //创建线程
                ThreadGroup tg = Thread.currentThread().getThreadGroup();
                for (ThreadGroup tgn = tg;
                     tgn != null;
                     tg = tgn, tgn = tg.getParent());
                Thread sft = new Thread(tg, proc, "Secondary finalizer");
                sft.start();
                try {
                    sft.join();
                } catch (InterruptedException x) {
                    /* Ignore */
                }
                return null;
                }});
    }

    //Runtime.runFinalization()调用,会启动线程,不断获取Finalizer,
    //然后调用runFinalizer方法从而调用对象的finalize方法
    static void runFinalization() {
        forkSecondaryFinalizer(new Runnable() {
            public void run() {
                for (;;) {
                    Finalizer f = (Finalizer)queue.poll();
                    if (f == null) break;
                    f.runFinalizer();
                }
            }
        });
    }

    /* Invoked by java.lang.Shutdown */
    static void runAllFinalizers() {
        forkSecondaryFinalizer(new Runnable() {
            public void run() {
                for (;;) {
                    Finalizer f;
                    synchronized (lock) {
                        f = unfinalized;
                        if (f == null) break;
                        unfinalized = f.next;
                    }
                    f.runFinalizer();
                }}});
    }
    //Finalizer线程-1,queue中不断remove,然后调用runFinalizer方法
    private static class FinalizerThread extends Thread {
        FinalizerThread(ThreadGroup g) {
            super(g, "Finalizer");
        }
        public void run() {
            for (;;) {
                try {
                    Finalizer f = (Finalizer)queue.remove();
                    f.runFinalizer();
                } catch (InterruptedException x) {
                    continue;
                }
            }
        }
    }

    static {
        ThreadGroup tg = Thread.currentThread().getThreadGroup();
        for (ThreadGroup tgn = tg;
             tgn != null;
             tg = tgn, tgn = tg.getParent());
        Thread finalizer = new FinalizerThread(tg);
        finalizer.setPriority(Thread.MAX_PRIORITY - 2);
        finalizer.setDaemon(true);
        finalizer.start();
    }

}

  • 注册:VM调用register方法,创建Finalizer,将该对象加入unfinalized链表;调用的时机有两个:先执行new分配好对象空间,然后再执行invokespecial调用构造函数,默认是构造函数返回之前调用Finalizer.register方法;如果通过-XX:-RegisterFinalizersAtInit关闭了该参数,那将在对象空间分配好之后将这个对象注册进去。
  • 需要GC销毁的对象会从unfinalized链放入ReferenceQueue队列中,这样剥离了该对象在链上的引用,
  • Finalizer线程-1,由static块启动,逻辑为:从queue中不断remove,然后调用runFinalizer方法
  • Finalizer线程-2,由Shutdown方法调用runAllFinalizers启动,逻辑为:遍历unfinalized链表,然后调用runFinalizer方法
  • Finalizer线程-2,由Runtime.runFinalization()调用启动,逻辑为:从queue中不断获取,然后调用runFinalizer方法
  • runFinalizer方法:若Finalizer包装的对象不为空且不为枚举,则调用执行其finalize方法(Object中定义),然后从unfinalized链表移除(等待被GC回收);将包装对象设置为null;若已经调用过,则不会再调用finalize方法。
  • GC时会将设置基类Reference中pending,后续将其加入到queue中,该queue是Finalizer的一个静态队列,保存了所有GC需要清理的强引用,后续调用runFinalizer方法,将从unfinalized链移除,引用置空。主要目的是清除引用,然后下次垃圾收集就会回收空间。

总结

posted @ 2017-02-27 20:42  尅皮埃  阅读(242)  评论(0)    收藏  举报