Java in a variety of reference (Reference) resolved

1, reference types

java.lang.refOverall package structure

java.lang.ref

Types of The corresponding class feature
Strong references Object strong references will not be recovered gc
Soft references SoftReference If the physical memory is not sufficient to be recovered gc, if physical memory is not sufficient then recycled gc.
Weak references WeakReference Once the scan is then recycled gc
False quote PhantomReference Will not affect the lifetime of the object, is tantamount to none, at any time are likely to be recovered gc
Final Reference For finishing mechanism (finalization)

2, Final Reference

FinalReferenceAccess for the package, and only one subclass Finalizer, while Finalizera final modified class, so expansion can not be inherited.

And Finalizerthe Object is associated with the finalize()method, during the loading of the class, if the current class has override finalize()method, it is marked as the object class finalizer, the object of this type may be recovered prior to its first call finalize().

Specific implementation mechanism, the reachability analysis gc time, if the current object is finalizer type and does not itself up (with reference to the attached non-GC Roots), will be added to a ReferenceQueuetype of queue (F-Queue) in. The system initialization process, will start a FinalizerThreadexample of a daemon thread (thread name Finalizer), the thread will continue to consume objects F-Queue in, and execute its finalize()methods (runFinalizer), and runFinalizer method captures Throwable level exception , that finalize()method does not result in abnormal FinalizerThreadoperation abort. Objects in the implementation of finalize()the method, you just break the Finalizerassociation, it does not mean that will be recovered immediately, or to wait for a GC under, and each object's finalize()methods will only be executed once, not repeated.

finalize()The method of the object is the last chance to escape the fate of death, if assigned to a class member variable or variable objects in the object for the method itself (this keyword), then it will be removed at the second mark "will recycling collection. "

- "in-depth understanding of java virtual machine"

Note: Improper finalize () can result in memory leaks and memory overflow, such as SocksSocketImplthe class of service will finalize()join the close()operation to free up resources, but if FinalizerThreadhas not been implemented, they would result in the release of resources have not been able, so a memory leak. If there is an object of finalize()the method execution time is too long or into an infinite loop will result F-Queuehas been the accumulation, causing memory overflow (oom).

2.1, Finalizer

  • FinalizerThread
    //消费ReferenceQueue并执行对应元素对象的finalize()方法
    private static class FinalizerThread extends Thread {
        ......
        public void run() {
            ......
            final JavaLangAccess jla = SharedSecrets.getJavaLangAccess();
            running = true;
            for (;;) {
                try {
                    Finalizer f = (Finalizer)queue.remove();
                    f.runFinalizer(jla);
                } catch (InterruptedException x) {
                }
            }
        }
    }
    //初始化的时候启动FinalizerThread(守护线程)
    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();
    }
  • add

It will start a daemon thread when jvm starts to consume a reference queue, queue and call references to an object's finalize () method.
jvm at the time of registration creates a finalize () method is overridden target Finalizerobject, and the object is added to a doubly linked list:

    static void register(Object finalizee) {
        new Finalizer(finalizee);
    }
    private Finalizer(Object finalizee) {
        super(finalizee, queue);
        add();
    }
    private void add() { 
        synchronized (lock) { //头插法构建Finalizer对象的链表
            if (unfinalized != null) {
                this.next = unfinalized;
                unfinalized.prev = this;
            }
            unfinalized = this;
        }
    }

There are also two additional threads for consumption Finalizer list and the queue:
Runtime.runFinalization()calls runFinalization()for consumption Finalizer queue, and java.lang.Shutdownwill in time jvm exit (jvm shutdown hook) calls runAllFinalizers()for consumption Finalizer list.

3, SoftReference

Before the system is going to happen out of memory (oom), will be recovered soft references, but also if there is not enough memory recovery, memory overflow exception is thrown;

Use SoftReference class, you will be the most soft reference object parameter passing;

Constructors ReferenceQueue incoming queue time, if the object reference is recovered, it is added to the queue.

public SoftReference(T referent)    根据传入的引用创建软引用                    
public SoftReference(T referent, ReferenceQueue<? super T> q)根据传入的引用和注册队列创建软引用

Example of use:

        ReferenceQueue<String> referenceQueue = new ReferenceQueue<>();
        SoftReference<String> softReference = new SoftReference<>("abc", referenceQueue);
        System.gc();
        System.out.println(softReference.get());
        Reference<? extends String> reference = referenceQueue.poll();
        System.out.println(reference);

Results are as follows:

abc
null

Soft reference cache can be used to implement memory-sensitive

4, WeakReference

WeakReferenceAnd SoftReferencesimilar, except that WeakReferencethe life cycle is shorter, occur once the GC will be recovered, but because gc thread priority is relatively low, it WeakReferencewill not soon be found and recovered GC.

Use WeakReferenceclass, will be the object of the most weak reference argument passed;

Constructors ReferenceQueue incoming queue time, if the object reference is recovered, it is added to the queue.

WeakReference(T referent)           根据传入的引用创建弱引用
WeakReference(T referent, ReferenceQueue<? super T> q) 根据传入的引用和注册队列创建弱引用

Example of use:

public class WeakReferenceTest {
    public static void main(String[] args) {
        ReferenceQueue<String> rq = new ReferenceQueue<>();
        //这里必须用new String构建字符串,而不能直接传入字面常量字符串
        Reference<String> r = new WeakReference<>(new String("java"), rq);
        Reference rf;
        //一次System.gc()并不一定会回收A,所以要多试几次
        while((rf=rq.poll()) == null) {
            System.gc();
        }
        System.out.println(rf);
        if (rf != null) {
            //引用指向的对象已经被回收,存入引入队列的是弱引用本身,所以这里最终返回null
            System.out.println(rf.get());
        }
    }
}

operation result:

java.lang.ref.WeakReference@5a07e868
null

5, PhantomReference

Virtual reference is a reference to the weakest type, exists in name only some of the mean reference. Different from the soft and weak references, phantom references will not affect the lifetime of the object, if a phantom reference object holds only, then it is not equivalent to a reference point, not up, gc to be scanned will be recovered, phantom reference unable to retrieve the target object by get () method so strong reference to the use of a target object, false references always get method returns null ().

And reference must reference the virtual queues (the ReferenceQueue) in combination, when gc is recovered a virtual object reference points, virtual reference refers will be added to the queue associated. It refers to the active virtual target tracking mainly for gc recovery , by reference to see whether the queue contains a virtual object corresponding to a reference to determine whether it is about to be recycled.

A virtual reference scenario is used to track activity recovered gc corresponding object.

public PhantomReference(T referent, ReferenceQueue<? super T> q)  创建弱引用

Example:

public class PhantomReferenceTest {

    public static void main(String[] args) {
        ReferenceQueue<String> rq = new ReferenceQueue<>();
        PhantomReference<String> reference = new PhantomReference<>(new String("cord"), rq);
        System.out.println(reference.get());
        System.gc();
        System.runFinalization();
        System.out.println(rq.poll() == reference);
    }
}

operation result:

null
true

6, ReferenceQueue

ReferenceQueue internal data structure is a linked list, the elements are added into the Reference Example, and then through waitand notifyAllachieve the object lock producers and consumers and, in this way simulate a queue.

ReferenceQueue using wati () and notifyAll () a specific scene mode to achieve both producers and consumers.

ReferenceQueue Key Source Analysis:

  • NULL and ENQUEUED
    static ReferenceQueue<Object> NULL = new Null<>();
    static ReferenceQueue<Object> ENQUEUED = new Null<>();

Both static properties mainly for references cited state flag is added to the queue, NULLidentifying that reference has been removed through the current queue, ENQUEUEDthe identifier of the current reference is added to the queue.

  • enqueue(Reference<? extends T> r)
    boolean enqueue(Reference<? extends T> r) { /* Called only by Reference class */
        synchronized (lock) {
            //检查该引用是否曾从当前队列移除过或者已经加入当前队列了,如果有则直接返回
            ReferenceQueue<?> queue = r.queue;
            if ((queue == NULL) || (queue == ENQUEUED)) {
                return false;
            }
            assert queue == this;
            r.queue = ENQUEUED;//将引用关联的队列统一标识为ENQUEUED
            r.next = (head == null) ? r : head;//当前引用指向head
            head = r; //将head指向当前引用(链表新增节点采用头插法)
            queueLength++; //更新链表长度
            if (r instanceof FinalReference) {
                sun.misc.VM.addFinalRefCount(1); //
            }
            lock.notifyAll(); //通知消费端
            return true;
        }
    }
  • remove(long timeout)

remove elements attempting to remove the head of the queue, if the queue is empty then waits until the specified timeout period.

    public Reference<? extends T> remove(long timeout)
        throws IllegalArgumentException, InterruptedException
    {
        if (timeout < 0) {
            throw new IllegalArgumentException("Negative timeout value");
        }
        synchronized (lock) {
            Reference<? extends T> r = reallyPoll();
            if (r != null) return r; //如果成功移除则直接返回
            long start = (timeout == 0) ? 0 : System.nanoTime();
            for (;;) {
                lock.wait(timeout); //释放当前线程锁,等待notify通知唤醒
                r = reallyPoll();
                if (r != null) return r;
                if (timeout != 0) {   //如果超时时间不为0则校验超时
                    long end = System.nanoTime();
                    timeout -= (end - start) / 1000_000;
                    if (timeout <= 0) return null;  //如果剩余时间小于0则返回
                    start = end;
                }
            }
        }
    }

7,Cleaner

Cleaner is PhantomReferencea sub-class implementation, provides more than finalization(收尾机制)more lightweight and robust implementation, because the clean-up logic Cleaner is a Reference.ReferenceHandlerdirect call, but also because it is a subclass of virtual reference, it will not affect the object pointed to life cycle.

Cleaner example a record of a reference object, and contains a clean logic Runnable examples. After Cleaner point of reference is recycled gc, Reference.ReferenceHandlerwe will continue to consume element queue reference, when the element Cleaner type of when it will call its clean () method.

Cleaner is not used as a substitute finalization, the only logical enough in cleaning up the lightweight and suitable for use when it is directly Cleaner, tedious and time-consuming cleanup logic will likely lead to ReferenceHandler thread blocks which delayed other cleanup tasks.

Key Source Analysis:

public class Cleaner extends PhantomReference<Object>
{
    //一个统一的空队列,用于虚引用构造方法,Cleaner的trunk会被直接调用不需要通过队列
    private static final ReferenceQueue<Object> dummyQueue = new ReferenceQueue<>();

    //Cleaner内部为双向链表,防止虚引用本身比它们引用的对象先被gc回收,此为头节点
    static private Cleaner first = null;

    //添加节点
    private static synchronized Cleaner add(Cleaner cl) {
        if (first != null) {    //头插法加入节点
            cl.next = first;
            first.prev = cl;
        }
        first = cl;
        return cl;
    }
    //移除节点
    private static synchronized boolean remove(Cleaner cl) {

        //指向自己说明已经被移除
        if (cl.next == cl)
            return false;

        //移除头部节点
        if (first == cl) {
            if (cl.next != null)
                first = cl.next;
            else
                first = cl.prev;
        }
        if (cl.next != null)//下一个节点指向前一个节点
            cl.next.prev = cl.prev;
        if (cl.prev != null)//前一个节点指向下一个节点
            cl.prev.next = cl.next;

        //自己指向自己标识已被移除
        cl.next = cl;
        cl.prev = cl;
        return true;

    }

    //清理逻辑runnable实现
    private final Runnable thunk;

    ...

    //调用清理逻辑
    public void clean() {
        if (!remove(this))
            return;
        try {
            thunk.run();
        } catch (final Throwable x) {
            ...
        }
    }
}

Cleaner can be used to achieve the outer heap memory management , DirectByteBufferis recovered by the external memory heap Cleaner achieved:

    DirectByteBuffer(int cap) { //构造方法中创建引用对象相关联的Cleaner对象                 
        ...
        cleaner = Cleaner.create(this, new Deallocator(base, size, cap));
        att = null;
    }
    
    private static class Deallocator implements Runnable {
        ...
        public void run() { //内存回收的逻辑(具体实现参看源码此处不展开)
        ...
        }

    }     

8, Reference

Reference is exemplified above several references including Cleaner common parent class, a number of general-purpose processing logic cited are achieved in the inside.

Several examples of the reference state

  • Active

    When in the Active state, special treatment will be referenced gc example, upon detection of a change gc reachability occurs, gc will change its state. At this point two cases, there are references to registration queue, it will enter the pending state if the reference instance is created, otherwise it will enter the inactive state. Reference the newly created instance to Active.

  • Pending

    Currently pending-Reference to an element in the list, waiting to be ReferenceHandler thread consumption and adding a reference to its registration queue. If the reference is a reference queue instance is not registered, it will never deal with the state.

  • Enqueued

    A register in the reference queue and the current state of the queue belonging to an element in the queue of the created instance referenced by this reference. When the reference is a reference example after removal from the queue register changes its state to Inactive. If the reference is a reference queue instance is not registered, it will never deal with the state.

  • Inactive

    When the Inactive state, without any treatment, once it becomes a state Inactive state will never change.

    Migration overall flow chart is as follows:

    Examples cited state

Key Source resolve

1, several key attributes of Reference

    //关联的对象的引用,根据引用类型不同gc针对性处理
    private T referent;       
    //引用注册的队列,如果有注册队列则回收引用会加入该队列
    volatile ReferenceQueue<? super T> queue;

    //上面引用队列referenceQueue中保存引用的链表
    /*    active:     NULL //未加入队列前next指向null
     *    pending:    this
     *    Enqueued:   next reference in queue (or this if last)
     *    Inactive:   this
     */
    Reference next;


    /* When active:   由gc管理的引用发现链表的下一个引用
     *     pending:   pending链表中的下一个元素
     *   otherwise:   NULL
     */
    transient private Reference<T> discovered;  /* used by VM */

    /* 
     *等待入队列的引用链表,gc往该链表加引用对象,Reference-handler线程消费该链表。
     * 它通过discovered连接它的元素 
     */     
    private static Reference<Object> pending = null;

2,ReferenceHandler

    private static class ReferenceHandler extends Thread {
        ...
        public void run() {
            while (true) {
                tryHandlePending(true); //无限循环调用tryHandlePending
            }
        }
    }
    static {
        ... jvm启动时以守护线程运行ReferenceHandler
        Thread handler = new ReferenceHandler(tg, "Reference Handler");
        handler.setPriority(Thread.MAX_PRIORITY);
        handler.setDaemon(true);
        handler.start();
        //注册JavaLangRefAccess匿名实现,堆外内存管理会用到(Bits.reserveMemory)
        SharedSecrets.setJavaLangRefAccess(new JavaLangRefAccess() {
            @Override
            public boolean tryHandlePendingReference() {
                return tryHandlePending(false);
            }
        });
    }
    //消费pending队列
    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...
                    //判断是否为Cleaner实例
                    c = r instanceof Cleaner ? (Cleaner) r : null;
                   //将r从pending链表移除
                    pending = r.discovered;
                    r.discovered = null;
                } else {
                    // The waiting on the lock may cause an OutOfMemoryError
                    // because it may try to allocate exception objects.
                    //如果pending没有元素可消费则等待通知
                    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清理逻辑(可参考前面的7,Cleaner段落)
        if (c != null) {
            c.clean();
            return true;
        }
        //如果当前引用实例有注册引用队列则将其加入引用队列
        ReferenceQueue<? super Object> q = r.queue;
        if (q != ReferenceQueue.NULL) q.enqueue(r);
        return true;
    }

to sum up

jvm referenced There are several types of realization, gc references for these types of different types have different recovery mechanisms, they also have their own application scenarios, such as SoftReference can be used for caching, WeakReference can also be used do some ordinary cache (WeakHashMap), while PhantomReference is used in some special scenes, such as Cleaner is a good scenario, it can be used to reclaim heap outside memory. At the same time, SoftReference, WeakReference, PhantomReference that several weak type reference may also be combined with the use of a reference cohort, making it possible to do some additional processing after recovery associated reference, even the Finalizer (finishing mechanism) can be recovered during the objects change the object's life cycle.

Reference links:

https://www.ibm.com/developerworks/cn/java/j-fv/index.html

https://www.infoq.cn/article/jvm-source-code-analysis-finalreference

https://www.ibm.com/developerworks/cn/java/j-lo-langref/index.html

https://www.cnblogs.com/duanxz/p/10275778.html

"In-depth understanding of java virtual machine"

https://blog.csdn.net/mazhimazh/article/details/19752475

https://www.tuicool.com/articles/AZ7Fvqb

https://blog.csdn.net/aitangyong/article/details/39455229

https://www.cnblogs.com/duanxz/p/6089485.html

https://www.throwable.club/2019/02/16/java-reference/#Reference set of states

http://imushan.com/2018/08/19/java/language/JDK%E6%BA%90%E7%A0%81%E9%98%85%E8%AF%BB-Reference/

Guess you like

Origin www.cnblogs.com/cord/p/11546303.html