Java四种引用包括强引用,软引用,弱引用,虚引用

0.由什么引出强引用、软引用、弱引用、虚引用

当我在写一个程序的时候,定义成员变量、写某个方法、定义局部变量、new对象的时候,这到底背后发生了什么?由此引发了JVM的内存模型。
这里我用箭头表示引发的一系列思考:JVM内存模型—>重点关注堆内存—>GC回收算法—>引用的四种类型。

1.强引用、软引用、弱引用、虚引用的含义及分析

强引用 :首先当 Object obj = new Object();当我使用new关键字的时候,就是一种强引用,表示任何时候都不会被回收。
软引用 :在java.lang.ref包下,有SoftReference类,当内存不足的时候,会被GC回收。
弱引用 :在java.lang.ref包下,有WeakReference类,是相对软引用来讲的,只要存在弱引用对象,那么不管内存是否足够,一定会被回收;
虚引用 :在java.lang.ref包下,有PhantomReference类,其顾名思义,形同虚设,任何时候都有可能被回收。;
Java四种引用包括强引用,软引用,弱引用,虚引用_第1张图片
看到这张图,大家可以联想到什么呢?
|
|
|
有没有想到Java的访问修饰符啊,同样给出图片
Java四种引用包括强引用,软引用,弱引用,虚引用_第2张图片
好了接下来,来分析源码,这里以SoftReference为例

import java.lang.ref.SoftReference;

public class SoftReferenceTest {
    public static void main(String[] args) {
        String str = new String("强引用");
        SoftReference softReference = new SoftReference(str);
        System.out.println("输出软引用:" + softReference);**加粗样式**
    }
}
package cn.fortune;


import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;

/**
 * @author   Mark Reinhold
 * @since    1.2
 */

public class SoftReference extends Reference {//这里继承Reference

    /**
     * Timestamp clock, updated by the garbage collector
     */
    static private long clock;

    /**
     * Timestamp updated by each invocation of the get method.  The VM may use
     * this field when selecting soft references to be cleared, but it is not
     * required to do so.
     */
    private long timestamp;

    /**
     * Creates a new soft reference that refers to the given object.  The new
     * reference is not registered with any queue.
     *
     * @param referent object the new soft reference will refer to
     */
    public SoftReference(T referent) {
        super(referent);
        this.timestamp = clock;
    }

    /**
     * Creates a new soft reference that refers to the given object and is
     * registered with the given queue.
     *
     * @param referent object the new soft reference will refer to
     * @param q the queue with which the reference is to be registered,
     *          or null if registration is not required
     *
     */
    public SoftReference(T referent, ReferenceQueue q) {
        super(referent, q);
        this.timestamp = clock;
    }

    /**
     * Returns this reference object's referent.  If this reference object has
     * been cleared, either by the program or by the garbage collector, then
     * this method returns null.
     *
     * @return   The object to which this reference refers, or
     *           null if this reference object has been cleared
     */
    public T get() {//这里是最最要的方法
        T o = super.get();
        if (o != null && this.timestamp != clock)
            this.timestamp = clock;
        return o;
    }

}

进一步,我再看一下,Reference这个类,具体信息(这里还可以看到两个关键字voliate与transient,大家知道它的用法吗?):



package cn.fortune;

import sun.misc.Cleaner;

import java.lang.ref.ReferenceQueue;

/**
 * @author   Mark Reinhold
 * @since    1.2
 */

public abstract class Reference {

    private T referent;         /* Treated specially by GC */

    volatile ReferenceQueue queue;
   
    Reference next;

    transient private Reference discovered;  /* used by VM */


    /* Object used to synchronize with the garbage collector.  The collector
     * must acquire this lock at the beginning of each collection cycle.  It is
     * therefore critical that any code holding this lock complete as quickly
     * as possible, allocate no new objects, and avoid calling user code.
     */
    static private class Lock { };
    private static Lock lock = new Lock();


    /* List of References waiting to be enqueued.  The collector adds
     * References to this list, while the Reference-handler thread removes
     * them.  This list is protected by the above lock object. The
     * list uses the discovered field to link its elements.
     */
    private static Reference pending = null;

    /* High-priority thread to enqueue pending References
     */
    private static class ReferenceHandler extends Thread {

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

        public void run() {
            for (;;) {
                Reference r;
                synchronized (lock) {
                    if (pending != null) {
                        r = pending;
                        pending = r.discovered;
                        r.discovered = null;
                    } else {
                        // The waiting on the lock may cause an OOME because it may try to allocate
                        // exception objects, so also catch OOME here to avoid silent exit of the
                        // reference handler thread.
                        //
                        // Explicitly define the order of the two exceptions we catch here
                        // when waiting for the lock.
                        //
                        // We do not want to try to potentially load the InterruptedException class
                        // (which would be done if this was its first use, and InterruptedException
                        // were checked first) in this situation.
                        //
                        // This may lead to the VM not ever trying to load the InterruptedException
                        // class again.
                        try {
                            try {
                                lock.wait();
                            } catch (OutOfMemoryError x) { }
                        } 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);
            }
        }
    }

    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
         */
        handler.setPriority(Thread.MAX_PRIORITY);
        handler.setDaemon(true);
        handler.start();
    }


    /* -- Referent accessor and setters -- */

    /**
     * Returns this reference object's referent.  If this reference object has
     * been cleared, either by the program or by the garbage collector, then
     * this method returns null.
     *
     * @return   The object to which this reference refers, or
     *           null if this reference object has been cleared
     */
    public T get() {
        return this.referent;
    }

    /**
     * Clears this reference object.  Invoking this method will not cause this
     * object to be enqueued.
     *
     * 

This method is invoked only by Java code; when the garbage collector * clears references it does so directly, without invoking this method. */ public void clear() { this.referent = null; } /* -- Queue operations -- */ /** * Tells whether or not this reference object has been enqueued, either by * the program or by the garbage collector. If this reference object was * not registered with a queue when it was created, then this method will * always return false. * * @return true if and only if this reference object has * been enqueued */ public boolean isEnqueued() { return (this.queue == ReferenceQueue.ENQUEUED); } /** * Adds this reference object to the queue with which it is registered, * if any. * *

This method is invoked only by Java code; when the garbage collector * enqueues references it does so directly, without invoking this method. * * @return true if this reference object was successfully * enqueued; false if it was already enqueued or if * it was not registered with a queue when it was created */ public boolean enqueue() { return this.queue.enqueue(this); } /* -- Constructors -- */ Reference(T referent) { this(referent, null); } Reference(T referent, ReferenceQueue queue) { this.referent = referent; this.queue = (queue == null) ? ReferenceQueue.NULL : queue; } }

软引用可以和一个引用队列(ReferenceQueue)联合使用,如果软引用所引用的对象被垃圾回收器回收,Java虚拟机就会把这个软引用加入到与之关联的引用队列中。

补充一下:
软引用主要用户实现类似缓存的功能,在内存足够的情况下直接通过软引用取值,无需从繁忙的真实来源查询数据,提升速度;当内存不足时,自动删除这部分缓存数据,从真正的来源查询这些数据。

弱引用主要用于监控对象是否已经被垃圾回收器标记为即将回收的垃圾,可以通过弱引用的isEnQueued方法返回对象是否被垃圾回收器标记。

虚引用是每次垃圾回收的时候都会被回收,通过虚引用的get方法永远获取到的数据为null,因此也被成为幽灵引用。
虚引用主要用于检测对象是否已经从内存中删除。

参考文献
[1]: https://blog.csdn.net/u010325193/article/details/80284444
[2]: https://www.cnblogs.com/yw-ah/p/5830458.html

你可能感兴趣的:(Java基础)