引用

当引用进入队列的时候,这个时候referent是为null?这个时候已经gc了吗---目前不清楚,可能处于要回收的阶段或者已经回收

当reference与referenQueue联合使用的主要作用就是当reference指向的referent回收时(或者要被回收 如下文要讲的Finalizer),提供一种通知机制,通过queue取到这些reference,来做额外的处理工作

从相应的设计思路来说,既然都进入到queue对象里面,就表示相应的对象需要被回收了,因为没有再访问原对象的必要。此方法不会由JVM调用,而JVM是直接通过字段操作清除相应的引用,其具体实现与当前方法相一致。


java 引用的介绍

对于reference和referent关系是 无论其实软,弱,虚,只要referent被gc(有可能在正在gc或者已经gc),我们的
reference就会被放进队列里面,区别就在于 软引用和弱引用都会影响referent被gc,前者是在jvm 多次gc之后内存不够的情况下回收referent对象,后者是只要发生gc referent就会被回收,而虚引用完全不影响referent的
gc

1.强引用:Object A=new Object();这种引用除非我们把他强制A=null 或者这不是一个全局变量 否则对象永远不会GC
2.软引用 SoftReference soft=new SoftReference(A) ,当A只有soft引用的时候,在内存实在不足时,会对软引用进行回收。但没有说清楚,到底什么时候会被回收。--就是这个软引用对象距离上次GC时一直没被使用的时间,如果这个时间大于_max_interval,说明这个软引用已经被废弃足够长时间了,被认为可以被回收了。其中SoftRefLRUPolicyMSPerMB默认1000,看来这个值和上次GC之后的剩余堆空间大小有关,可用空间越大,_max_interval就越大。
如果GC之后,堆的可用空间还很大的话,SoftReference对象可以长时间的在堆中而不被回收。反之,如果GC之后,只剩下10M可用,那么SoftReference对象可被废弃的时间也是可以算出来的。

3.弱引用 WeakReference weak=new WeakReference(A) ,当A只有weak引用的时候,其会在jvm发生gc(无论是minor ,major,full gc)之后被回收
4.虚引用,不影响对象的被回收,一般很多框架中用他来回收资源,比如一些数据库连接的回收

public abstract class Reference {

   Reference 有四种状态 active,pending enqueued inactive
   所有的引用刚new出来的时候都是active,如果某个reference new的时候没有传递队列
   那么当其被gc的时候 是默认进入inactive,携带队列的reference,会在被gc的时候进入pending,
   然后进入enqueued,从队列出来就inactive

   我们引用包裹的对象referent
    private T referent;         /* Treated specially by GC */

    存放referent被gc时候 reference存放进入queue
    volatile ReferenceQueue queue;
    当reference是active 其next是null 进入pending的时候 next 是自己
    进入队列的时候next是队列的下一个 ,inactvie的是next是自己
    @SuppressWarnings("rawtypes")
    Reference next;

        当是active的时候 他的下一个元素在 a discovered reference list(gc操作的)或者是自身 如果是最后一个
        当当前对象是pending的时候 discovered的下一个元素在pending list 或者为null 如果是最后一个
    其他的都是null
    标识表示要处理的对象的下一个对象,如果只有一个对象了 那就是这个对象本身
   transient private Reference discovered;  /* used by VM */


    
    static private class Lock { }
    private static Lock lock = new Lock();


   标识我们正在gc 要放入队列对象
    private static Reference pending = null;

    //预加载并初始化InterruptedException和Cleaner类
             //这样我们就不会在运行循环中遇到麻烦了
             //懒惰加载/初始化时内存不足
    private static class ReferenceHandler extends Thread {

        private static void ensureClassInitialized(Class clazz) {
            try {
                Class.forName(clazz.getName(), true, clazz.getClassLoader());
            } catch (ClassNotFoundException e) {
                throw (Error) new NoClassDefFoundError(e.getMessage()).initCause(e);
            }
        }

        static {
          
            ensureClassInitialized(InterruptedException.class);
            ensureClassInitialized(Cleaner.class);
        }

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

        public void run() {
            while (true) {
            不停的处理pending
                tryHandlePending(true);
            }
        }
    }

    static boolean tryHandlePending(boolean waitForNotify) {
        Reference r;
        Cleaner c;
        try {
            synchronized (lock) {
            首先加锁
                if (pending != null) {
                说明有referent被gc 或者正在gc
                    r = pending;
                   确定是否是cleaner
                    c = r instanceof Cleaner ? (Cleaner) r : null;
                    // unlink 'r' from 'pending' chain
                    吧pending 的下一个赋值给pending
                    pending = r.discovered;
                    置空该discover 这样  r 就可以正常被回收
                    r.discovered = null;
                } else {
                    // The waiting on the lock may cause an OutOfMemoryError
                    // because it may try to allocate exception objects.
                    如果pending ==null 看看是否需要wait
                    if (waitForNotify) {
                        lock.wait();
                    }
                    // retry if waited
                    return waitForNotify;
                }
            }
        } catch (OutOfMemoryError x) {
         让出cpu
            Thread.yield();
            // retry
            return true;
        } catch (InterruptedException x) {
            // retry
            return true;
        }

       如果是cleaner 就执行cleaner的方法,回收堆外内存
        if (c != null) {
            c.clean();
            return true;
        }
否则就进入ReferenceQueue队列
        ReferenceQueue q = r.queue;
        if (q != ReferenceQueue.NULL) q.enqueue(r);
        return true;
    }
    当reference类被classloader的时候会执行下面的方法
    static {
    规定一个线程组
        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
         */
         new 一个ReferenceHandler线程 设置优先级和daemon模式
        handler.setPriority(Thread.MAX_PRIORITY);
        handler.setDaemon(true);
        handler.start();

        // provide access in SharedSecrets
        SharedSecrets.setJavaLangRefAccess(new JavaLangRefAccess() {
            @Override
            public boolean tryHandlePendingReference() {
                return tryHandlePending(false);
            }
        });
    }

 

}
 
 

threadLocalMap的key是 weakReference(Entry的key) 该对象内部持有threadlocal

当threadlocal对象没有GCRoot对其进行强引用 那么被weakReference持有的threadlocal会在gc之后被回收,
而对应的weakReference会被放入referenceQueue(如果队列为空就不放),那么这个是weakReference不是为null。
因为weakReference本身也是java对象 他要被回收必须是没有GCRoot链接weakReference,因此我们一般情况下threadlocal都是使用全局变量,所以一般threadlocal无法为null。
对于我们来说无论是虚,弱,软三个引用 都是在他们持有的对象被回收之后放入队列,区别在于虚引用不影响对象gc,弱引用在对象gc,软引用在内存不足的时候。

你可能感兴趣的:(引用)